From 82713327db7f68680ac0a027cc80b6e108fa5b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=8C=E5=85=88=E8=88=9C?= <2499071264@qq.com> Date: Mon, 26 Oct 2026 09:19:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20v3=E7=89=88=E7=96=97=E4=BC=91=E5=85=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/budwk/app/MainLauncher.java | 1 + .../TherapyRecuperationModule.java | 190 + .../common/TherapyRecuperationCommon.java | 32 + ...pyRecuperationJoinUserImportExcelMode.java | 24 + .../TheRapyRecuperationLineCreateMode.java | 33 + .../TheRapyRecuperationProvinceType.java | 31 + .../TheRapyRecuperationSignUpMode.java | 34 + .../constant/TheRapyRecuperationState.java | 39 + .../constant/TheRapyRecuperationType.java | 70 + .../controller/TherapyCommonController.java | 149 + .../TherapyWorkspaceController.java | 32 + .../TheRapyRecuperationAuditController.java | 617 ++ ...RapyRecuperationTravelAuditController.java | 237 + ...TheRapyRecuperationXghAuditController.java | 355 + ...RapyRecuperationBaseManagerController.java | 360 + .../TheRapyRecuperationLineController.java | 708 ++ ...apyRecuperationTravelAgencyController.java | 279 + ...leTheRapyRecuperationEnrollController.java | 74 + .../TheRapyRecuperationEnrollController.java | 501 ++ ...erationEnrollJoinUserImportController.java | 166 + .../TheRapyRecuperationExamineController.java | 18 + ...yRecuperationLineAdjustmentController.java | 207 + ...RapyRecuperationLineClusterController.java | 128 + ...rationLineSelectionOverviewController.java | 461 ++ ...RecuperationLineUnionSelectController.java | 447 + ...eRapyRecuperationStatisticsController.java | 153 + ...eRapyRecuperationUnionQueryController.java | 1093 +++ ...heRapyRecuperationUserQueryController.java | 1348 +++ ...yRecuperationLineStatisticsController.java | 501 ++ ...avelAgencyMonthlyStatisticsController.java | 177 + .../TheRapyRecuperationConfigController.java | 144 + .../job/SendTakePartInUserByLineJob.java | 145 + .../job/SendTakePartInUserByTravelJob.java | 113 + .../mode/TheRapyLineImportExcelMode.java | 53 + .../mode/TheRapyLineImportImageMode.java | 30 + .../TheRapyRecuperationEnrollExcelMode.java | 22 + .../mode/TheRapyTravelAgencyExcelMode.java | 39 + .../mode/TheRapyTravelLineExcelMode.java | 69 + .../TheRapyRecuperationBaseManagement.java | 158 + .../model/TheRapyRecuperationCluster.java | 40 + .../TheRapyRecuperationClusterMember.java | 60 + .../model/TheRapyRecuperationConfig.java | 164 + .../model/TheRapyRecuperationEnroll.java | 207 + .../model/TheRapyRecuperationEnrollBed.java | 48 + ...TheRapyRecuperationEnrollChangeRecord.java | 37 + .../TheRapyRecuperationEnrollCompanion.java | 79 + .../model/TheRapyRecuperationLine.java | 160 + .../TheRapyRecuperationLineUnionSelect.java | 158 + .../model/TheRapyRecuperationLot.java | 47 + .../TheRapyRecuperationTravelAgency.java | 94 + .../vo/LineSelectionOverviewTimeSlotVo.java | 105 + .../model/vo/LineSelectionOverviewVo.java | 87 + ...TravelAgencyMonthlyEnrollStatisticsVo.java | 42 + .../model/vo/UnionEnrollStatisticsVo.java | 42 + .../model/vo/UnionLineNumberStatisticsVo.java | 47 + .../model/vo/UnionLineSelectLimitVo.java | 32 + .../TheRapyRecuperationAuditService.java | 40 + .../TheRapyRecuperationCommonService.java | 17 + ...cuperationEnrollJoinUserImportService.java | 15 + .../TheRapyRecuperationEnrollService.java | 229 + ...RapyRecuperationLineAdjustmentService.java | 16 + ...TheRapyRecuperationLineClusterService.java | 40 + .../TheRapyRecuperationLineService.java | 107 + ...apyRecuperationLineUnionSelectService.java | 108 + ...heRapyRecuperationTravelAgencyService.java | 79 + ...TheRapyRecuperationBaseManagerService.java | 13 + .../TheRapyRecuperationAuditServiceImpl.java | 169 + .../TheRapyRecuperationCommonServiceImpl.java | 66 + ...rationEnrollJoinUserImportServiceImpl.java | 79 + .../TheRapyRecuperationEnrollServiceImpl.java | 2376 ++++++ ...RecuperationLineAdjustmentServiceImpl.java | 140 + ...apyRecuperationLineClusterServiceImpl.java | 262 + .../TheRapyRecuperationLineServiceImpl.java | 643 ++ ...ecuperationLineUnionSelectServiceImpl.java | 476 ++ ...pyRecuperationTravelAgencyServiceImpl.java | 124 + ...apyRecuperationBaseManagerServiceImpl.java | 68 + .../support/LegacyBaseModel.java | 20 + .../therapyRecuperation/support/PageUtil.java | 7 + .../support/SelectEnum.java | 7 + .../support/TherapyAudit.java | 29 + .../support/TherapyAuditState.java | 15 + .../support/TherapyContext.java | 95 + .../support/TherapyDataService.java | 11 + .../support/TherapyDownload.java | 13 + .../support/TherapyEmail.java | 117 + .../support/TherapyMessage.java | 28 + .../support/TherapyReturnConfiguration.java | 43 + .../support/TherapyService.java | 10 + .../support/TherapyServiceImpl.java | 22 + .../support/TherapyUnion.java | 18 + .../support/TherapyUser.java | 41 + .../therapyRecuperation/support/ViReturn.java | 10 + .../init_staff_therapy_recuperation.sql | 687 ++ .../staffbenefit/therapyRecuperation/basic.js | 185 + .../therapyRecuperation/basics.js | 125 + .../therapyRecuperation/compat.js | 42 + .../therapyRecuperation/component.js | 129 + .../therapyRecuperation/css/common.css | 198 + .../therapyRecuperation/css/elmain.css | 152 + .../therapyRecuperation/css/main.css | 7348 +++++++++++++++++ .../therapyRecuperation/css/panel.css | 283 + .../therapyRecuperation/img/in.png | Bin 0 -> 6172 bytes .../therapyRecuperation/img/index1.jpeg | Bin 0 -> 61961 bytes .../therapyRecuperation/img/loading.gif | Bin 0 -> 10118 bytes .../therapyRecuperation/img/lxs.png | Bin 0 -> 9872 bytes .../therapyRecuperation/img/out.png | Bin 0 -> 7906 bytes .../therapyRecuperation/img/title.png | Bin 0 -> 16761 bytes .../therapyRecuperation/initTableMixins.js | 166 + .../therapyRecuperation/mobile/main.css | 119 + .../therapyRecuperation/mobile/theme.css | 177 + .../therapyRecuperation/mobileMixins.js | 98 + .../therapyRecuperation/svg/top.svg | 1 + .../templates/TravelAgencyImport.xlsx | Bin 0 -> 9172 bytes .../templates/TravelEnrollImport.xlsx | Bin 0 -> 8813 bytes .../staffbenefit/therapyRecuperation/v.js | 426 + .../therapyRecuperation/BaseManageInfo.vue | 104 + .../therapyRecuperation/BorderTable.vue | 82 + .../therapyRecuperation/DrawerUserScope.vue | 10 + .../therapyRecuperation/Enrollinfo.vue | 191 + .../therapyRecuperation/FileUpload.vue | 42 + .../therapyRecuperation/Guava.vue | 146 + .../therapyRecuperation/ImageUpload.vue | 42 + .../therapyRecuperation/LineInfo.vue | 145 + .../therapyRecuperation/XghEnrollInfo.vue | 158 + .../therapyRecuperation/mobile/MCard.vue | 50 + .../therapyRecuperation/mobile/MLoading.vue | 89 + .../mobile/MTableLoading.vue | 140 + .../mobile/VantFileUpload.vue | 671 ++ .../therapyRecuperation/lxy_cxry.xlsx | Bin 0 -> 11284 bytes .../therapyRecuperation/lxy_sbb.xlsx | Bin 0 -> 11312 bytes .../audit/TheRapyAudit.html | 978 +++ .../audit/TheRapyTravelAudit.html | 806 ++ .../audit/TheRapyXghAudit.html | 974 +++ .../baseManage/baseManagement.html | 698 ++ .../therapyRecuperation/basicManage/line.html | 1048 +++ .../basicManage/travelAgency.html | 473 ++ .../therapyRecuperation/index.html | 5 + .../therapyRecuperation/layouts/mobile.html | 23 + .../therapyRecuperation/layouts/platform.html | 42 + .../process/TheRapyQuery.html | 1771 ++++ .../process/TheRapyUserQuery.html | 1493 ++++ .../process/joinUserImport.html | 276 + .../process/lineAdjustment.html | 451 + .../process/lineCluster.html | 516 ++ .../process/lineSelectionOverview.html | 687 ++ .../process/lineUnionSelect.html | 892 ++ .../process/queryStatics.html | 231 + .../statistics/lineStatistics.html | 804 ++ .../travelAgencyMonthlyStatistics.html | 278 + .../statistics/unionLineNumberStatistics.html | 93 + .../theRapyConfig/TheRapyConfig.html | 573 ++ .../therapyRecuperation/baseManagement.html | 651 ++ .../therapyRecuperation/index.html | 165 + .../therapyRecuperation/lineInfo.html | 896 ++ .../therapyRecuperation/lineList.html | 911 ++ .../therapyRecuperation/myRecuperation.html | 586 ++ .../therapyRecuperation/userSignInfo.html | 84 + 157 files changed, 44651 insertions(+) create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/TherapyRecuperationModule.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/common/TherapyRecuperationCommon.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationJoinUserImportExcelMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationLineCreateMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationProvinceType.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationSignUpMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationState.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationType.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyCommonController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyWorkspaceController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationAuditController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationTravelAuditController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationXghAuditController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/mobile/MobileTheRapyRecuperationEnrollController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollJoinUserImportController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationExamineController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineAdjustmentController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineClusterController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineSelectionOverviewController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineUnionSelectController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationStatisticsController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUnionQueryController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUserQueryController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationLineStatisticsController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationTravelAgencyMonthlyStatisticsController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/theRapyConfig/TheRapyRecuperationConfigController.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByLineJob.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByTravelJob.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportExcelMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportImageMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyRecuperationEnrollExcelMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelLineExcelMode.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationBaseManagement.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationCluster.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationClusterMember.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationConfig.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnroll.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollBed.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollChangeRecord.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollCompanion.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLine.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLineUnionSelect.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLot.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationTravelAgency.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewTimeSlotVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/TravelAgencyMonthlyEnrollStatisticsVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionEnrollStatisticsVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineNumberStatisticsVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineSelectLimitVo.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationAuditService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationCommonService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollJoinUserImportService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineAdjustmentService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineClusterService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineUnionSelectService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationTravelAgencyService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/baseManage/TheRapyRecuperationBaseManagerService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationAuditServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationCommonServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollJoinUserImportServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineAdjustmentServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineClusterServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineUnionSelectServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationTravelAgencyServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/LegacyBaseModel.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/PageUtil.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/SelectEnum.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAudit.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAuditState.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyContext.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDataService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDownload.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyEmail.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyMessage.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyReturnConfiguration.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyService.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyServiceImpl.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUnion.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUser.java create mode 100644 src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/ViReturn.java create mode 100644 src/main/resources/db/v4_from_v3/init_staff_therapy_recuperation.sql create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/basic.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/basics.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/compat.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/common.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/elmain.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/main.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/panel.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/in.png create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/index1.jpeg create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/loading.gif create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/lxs.png create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/out.png create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/title.png create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/initTableMixins.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/main.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/theme.css create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobileMixins.js create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/svg/top.svg create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelAgencyImport.xlsx create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelEnrollImport.xlsx create mode 100644 src/main/resources/static/assets/staffbenefit/therapyRecuperation/v.js create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/BaseManageInfo.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/BorderTable.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/DrawerUserScope.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/Enrollinfo.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/FileUpload.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/Guava.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/ImageUpload.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/LineInfo.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/XghEnrollInfo.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MCard.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MLoading.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MTableLoading.vue create mode 100644 src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/VantFileUpload.vue create mode 100644 src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_cxry.xlsx create mode 100644 src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_sbb.xlsx create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/index.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/mobile.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/platform.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyQuery.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyUserQuery.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html create mode 100644 src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/index.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html create mode 100644 src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html diff --git a/src/main/java/com/budwk/app/MainLauncher.java b/src/main/java/com/budwk/app/MainLauncher.java index b220ad2..c717fcd 100644 --- a/src/main/java/com/budwk/app/MainLauncher.java +++ b/src/main/java/com/budwk/app/MainLauncher.java @@ -83,6 +83,7 @@ public class MainLauncher { Globals.AppBase = Mvcs.getServletContext().getContextPath(); Globals.AppRoot = Mvcs.getServletContext().getRealPath("/"); init_sys(); + ioc.get(com.budwk.app.zhgh.staffbenefit.therapyRecuperation.TherapyRecuperationModule.class); // 2026年10月3日 12:01:28;操作人:wxg:先升级会员表及补齐历史资料,再处理缴费快照和启动计划任务;不依赖 DEBUG。 SysClubUserService members = ioc.get(SysClubUserService.class, "sysClubUserServiceImpl"); members.upgradeMemberSchema(); diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/TherapyRecuperationModule.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/TherapyRecuperationModule.java new file mode 100644 index 0000000..d0d0bd2 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/TherapyRecuperationModule.java @@ -0,0 +1,190 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation; + +import com.budwk.app.sys.models.*; +import com.budwk.app.sys.services.SysMenuService; +import com.budwk.app.sys.services.SysRoleService; +import com.budwk.app.sys.services.SysUserService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.*; +import org.nutz.dao.*; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.trans.Trans; + +import java.util.*; + +@IocBean(create = "init") +public class TherapyRecuperationModule { + public static final String ROOT = "/platform/staffTherapyRecuperation"; + public static final String[][] SCREENS = { + {"config", "基础设置", "/TheRapyConfig", "TheRapyConfig"}, + {"agency", "旅行社管理", "/travelAgency", "travelAgency"}, + {"line", "线路管理", "/line", "line"}, + {"base", "目的地管理", "/baseManagement", "TheBaseManagement"}, + {"branchSelect", "分工会选择线路", "/lineFghSelect?mode=1", "lineFghSelect"}, + {"schoolSelect", "校工会选择线路", "/lineXghSelect?mode=2", "lineXghSelect"}, + {"overview", "线路选择总览", "/lineSelectionOverview", "lineSelectionOverview"}, + {"cluster", "线路组团", "/lineCluster", "lineCluster"}, + {"adjustment", "线路调剂", "/lineAdjustment", "line.adjustment"}, + {"import", "参加人员导入", "/joinUserImport", "joinUser.import"}, + {"branchAudit", "分工会审核", "/TheRapyAudit", "TheRapyAudit"}, + {"travelAudit", "自由组团审核", "/TheRapyTravelAudit", "TheRapyTravelAudit"}, + {"schoolAudit", "校工会审核", "/TheRapyXghAudit", "TheRapyXghAudit"}, + {"branchQuery", "分工会查询", "/query", "TheRapyQuery"}, + {"userQuery", "报名人员查询", "/user/query", "TheRapyUserQuery"}, + {"queryStatistics", "查询统计", "/query/statics", "queryStatics"}, + {"lineStatistics", "线路统计", "/statistics", "statistics"}, + {"agencyStatistics", "旅行社月度统计", "/travelAgencyMonthlyStatistics", "travelAgencyMonthlyStatistics"}, + {"unionStatistics", "分工会线路数量统计", "/statistics/unionLineNumberStatistics", "unionLineNumberStatistics"} + }; + + @Inject + private Dao dao; + @Inject + private SysMenuService sysMenuService; + @Inject + private SysRoleService sysRoleService; + @Inject + private SysUserService sysUserService; + + public void init() { + Class[] tables = {TheRapyRecuperationBaseManagement.class, TheRapyRecuperationCluster.class, + TheRapyRecuperationClusterMember.class, TheRapyRecuperationConfig.class, + TheRapyRecuperationEnroll.class, TheRapyRecuperationEnrollBed.class, + TheRapyRecuperationEnrollChangeRecord.class, TheRapyRecuperationEnrollCompanion.class, + TheRapyRecuperationLine.class, TheRapyRecuperationLineUnionSelect.class, + TheRapyRecuperationLot.class, TheRapyRecuperationTravelAgency.class, + TherapyAudit.class, TherapyAuditState.class}; + for (Class table : tables) dao.create(table, false); + createView("staff_therapy_user", "SELECT u.*, u.arrivalAtSchoolDate AS schoolTime FROM vw_user u"); + createView("staff_therapy_union", "SELECT u.*, u.name AS unionname FROM sys_union u"); + createView("staff_therapy_unit", "SELECT u.* FROM sys_unit u"); + Trans.exec(() -> { + seedStates(); + seedVersion(); + seedConfig(); + seedMenus(); + }); + } + + private void createView(String name, String select) { + org.nutz.dao.sql.Sql exists = Sqls.create("SELECT COUNT(1) FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name=@name"); + exists.setParam("name", name); + exists.setCallback(Sqls.callback.integer()); + dao.execute(exists); + if (exists.getInt() == 0) dao.execute(Sqls.create("CREATE VIEW " + name + " AS " + select)); + } + + private void seedStates() { + int[] ids = {2710, 2715, 2720, 2725, 2730, 2735, 2750}; + String[] names = {"待分工会审核", "分工会审核不通过", "待选择线路分工会审核", "选择线路分工会不通过", + "待校工会审核", "校工会审核不通过", "审核通过"}; + for (int i = 0; i < ids.length; i++) { + if (dao.fetch(TherapyAuditState.class, ids[i]) != null) continue; + TherapyAuditState state = new TherapyAuditState(); + state.setStateId(ids[i]); + state.setStateName(names[i]); + state.setStateColor(ids[i] == 2750 ? "#67c23a" : ids[i] % 10 == 5 ? "#f56c6c" : "#e6a23c"); + dao.insert(state); + } + } + + private void seedVersion() { + if (dao.fetch(Sys_config.class, "staffTherapyRecuperationVersion") != null) return; + Sys_config setting = new Sys_config(); + setting.setConfigKey("staffTherapyRecuperationVersion"); + setting.setConfigValue("zjnu"); + setting.setNote("职工疗休养独立子模块报名规则版本"); + dao.insert(setting); + } + + private void seedConfig() { + if (dao.count(TheRapyRecuperationConfig.class) != 0) return; + TheRapyRecuperationConfig config = new TheRapyRecuperationConfig(); + config.setConfigName("智慧工会疗休养配置"); + config.setIsSnLine(false); + config.setIsSwLine(false); + config.setTravelAudit(false); + config.setBedInfo(true); + config.setFamilyInfo(1); + config.setOutsideQuotaProportion(0D); + config.setUnionLineNumberConfigs(new ArrayList<>()); + dao.insert(config); + } + + private void seedMenus() { + Sys_menu existing = dao.fetch(Sys_menu.class, Cnd.where("href", "like", "/platform/recuperation%").and("platform", "=", "pc")); + Sys_module module = existing == null ? null : dao.fetch(Sys_module.class, existing.getModuleId()); + if (module == null) module = dao.fetch(Sys_module.class, Cnd.where("name", "=", "职工福利").and("platform", "=", "pc")); + if (module == null) { + module = new Sys_module(); + module.setName("职工福利"); + module.setPlatform("pc"); + module.setSortNum(50); + module.setFaIcon("fa fa-heart"); + dao.insert(module); + } + Sys_menu root = addMenu(module.getId(), "", "职工疗休养", ROOT, "staffTherapyRecuperation", "pc"); + List roles = dao.query(Sys_role.class, Cnd.where("disabled", "=", false)); + for (String[] screen : SCREENS) { + Sys_menu menu = addMenu(module.getId(), root.getId(), screen[1], ROOT + "?screen=" + screen[0], + "staffTherapyRecuperation." + screen[3], "pc"); + for (Sys_role role : roles) { + String code = role.getCode(); + boolean school = List.of("sysadmin", "superadmin", "A06", "SchoolUnionMemberAdmin", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "SCHOOL_UNION_MEMBER_ADMIN").contains(code); + boolean branch = List.of("H03", "H04", "H06", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN").contains(code) + && Set.of("line", "base", "branchSelect", "branchAudit", "travelAudit", "branchQuery", "overview", "cluster", "adjustment").contains(screen[0]); + if (school || branch) { + grant(role.getId(), root.getId()); + grant(role.getId(), menu.getId()); + } + } + } + Sys_menu signup = addMenu(module.getId(), root.getId(), "疗休养报名", ROOT + "?screen=signup", "staffTherapyRecuperation.signup", "pc"); + Sys_module h5Module = dao.fetch(Sys_module.class, Cnd.where("name", "=", module.getName()).and("platform", "=", "h5")); + if (h5Module == null) { + h5Module = new Sys_module(); + h5Module.setName(module.getName()); + h5Module.setPlatform("h5"); + h5Module.setSortNum(module.getSortNum()); + h5Module.setFaIcon("fa fa-heart"); + dao.insert(h5Module); + } + Sys_menu mobile = addMenu(h5Module.getId(), "", "职工疗休养", ROOT + "/mobile/index", "staffTherapyRecuperation.mobile", "h5"); + for (Sys_role role : roles) { + if (List.of("public", "PUBLIC", "MEMBER", "sysadmin", "superadmin", "SYSADMIN").contains(role.getCode())) { + grant(role.getId(), root.getId()); + grant(role.getId(), signup.getId()); + grant(role.getId(), mobile.getId()); + } + } + sysMenuService.clearCache(); + sysRoleService.clearCache(); + sysUserService.clearCache(); + } + + private Sys_menu addMenu(String moduleId, String parentId, String name, String href, String permission, String platform) { + Sys_menu menu = dao.fetch(Sys_menu.class, Cnd.where("permission", "=", permission)); + if (menu != null) return menu; + menu = new Sys_menu(); + menu.setModuleId(moduleId); + menu.setName(name); + menu.setHref(href); + menu.setPermission(permission); + menu.setPlatform(platform); + menu.setType("menu"); + menu.setTarget("_self"); + menu.setIcon("fa fa-heart"); + menu.setShowit(true); + menu.setDisabled(false); + sysMenuService.save(menu, parentId, Collections.emptyList()); + return menu; + } + + private void grant(String roleId, String menuId) { + if (dao.count("sys_role_menu", Cnd.where("roleId", "=", roleId).and("menuId", "=", menuId)) == 0) { + dao.insert("sys_role_menu", Chain.make("roleId", roleId).add("menuId", menuId)); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/common/TherapyRecuperationCommon.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/common/TherapyRecuperationCommon.java new file mode 100644 index 0000000..4ba4af6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/common/TherapyRecuperationCommon.java @@ -0,0 +1,32 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; + +public class TherapyRecuperationCommon { + + public static String getRemarkBySchoolTime(String schoolTime) { + if(StrUtil.isNotBlank(schoolTime)) { + + String[] patterns = { + "yyyy-MM-dd", + "yyyy/MM/dd", + "yyyy-MM", + "yyyy/MM", + "yyyyMM", + "yyyyMMdd", + "yyyy年MM月dd日", + "yyyy年M月d日" + }; + + DateTime schoolDate = DateUtil.parse(schoolTime, patterns); + DateTime time = DateUtil.parse(DateUtil.thisYear() + "-07-01"); + int compareResult = DateUtil.compare(schoolDate, time); + return compareResult >= 0 ? ("入校时间为:" + schoolTime + ",疗休养额度为1500。") : ""; + } else { + return ""; + } + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationJoinUserImportExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationJoinUserImportExcelMode.java new file mode 100644 index 0000000..b10c5d6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationJoinUserImportExcelMode.java @@ -0,0 +1,24 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.util.Date; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationJoinUserImportExcelMode + * @Description: 参加人员导入excel mode + * @Author zxc + * @Date 2022/6/14:11:10 + * @Version V1.0 + **/ +@Data +public class TheRapyRecuperationJoinUserImportExcelMode { + + @Excel(name = "工号") + private String loginName; + + @Excel(name = "参加时间", format = "yyyyMMdd") + private Date takePartInTime; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationLineCreateMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationLineCreateMode.java new file mode 100644 index 0000000..1fd146e --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationLineCreateMode.java @@ -0,0 +1,33 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode + * @Description: 线路创建模式 + * @Author zxc + * @Date 2022/6/2:15:22 + * @Version V1.0 + **/ +@AllArgsConstructor +@Getter +@SelectEnum +public enum TheRapyRecuperationLineCreateMode { + + /** + * 分工会 + */ + UNION(1, "分工会"), + + /** + * 校工会 + */ + SCHOOL(2, "校工会"); + + + private final int value; + private final String label; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationProvinceType.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationProvinceType.java new file mode 100644 index 0000000..8b82020 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationProvinceType.java @@ -0,0 +1,31 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType + * @Description: TODO + * @Author zxc + * @Date 2022/6/2:14:08 + * @Version V1.0 + **/ +@AllArgsConstructor +@Getter +@SelectEnum +public enum TheRapyRecuperationProvinceType { + /** + * 省内 + */ + provinceIn("省内线路", "省内"), + + /** + * 省外 + */ + provinceOut("省外线路", "省外"); + + private final String label; + private final String value; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationSignUpMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationSignUpMode.java new file mode 100644 index 0000000..7118110 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationSignUpMode.java @@ -0,0 +1,34 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode + * @Description: 报名模式 + * @Author zxc + * @Date 2022/6/2:15:22 + * @Version V1.0 + **/ +@AllArgsConstructor +@Getter +@SelectEnum +public enum TheRapyRecuperationSignUpMode { + + /** + * 分工会模式 + */ + UNION(1, "分工会组织", new String[]{"H04", "A06", "sysadmin"}), + + /** + * 自由模式 + */ + FREE(2, "校工会组织", new String[]{"A06", "sysadmin"}); + + + private final int value; + private final String label; + private final String[] roles; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationState.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationState.java new file mode 100644 index 0000000..5993ec9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationState.java @@ -0,0 +1,39 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +/** + * 审核状态 + */ +public interface TheRapyRecuperationState { + + /** + * 待分工会审核 + */ + Integer UNIT = 2710; + /** + * 分工会审核不通过 + */ + Integer UNITFAIL = 2715; + /** + * 待选择线路分工会审核 + */ + Integer LINEUNIT = 2720; + /** + * 选择线路分工会不通过 + */ + Integer LINEUNITFAIL = 2725; + + /** + * 待校工会审核 + */ + Integer SCHOOL = 2730; + /** + * 校工会审核不通过 + */ + Integer SCHOOLFAIL = 2735; + + /** + * 审核通过 + */ + Integer PASS = 2750; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationType.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationType.java new file mode 100644 index 0000000..93ff2e9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/constant/TheRapyRecuperationType.java @@ -0,0 +1,70 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.SelectEnum; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.HashMap; +import java.util.Map; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType + * @Description: 疗休养分类 + * @Author zxc + * @Date 2022/6/2:14:02 + * @Version V1.0 + **/ +@AllArgsConstructor +@Getter +@SelectEnum +public enum TheRapyRecuperationType { + /** + * 省内线路 + */ + provinceInLine("省内线路", 0, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/in.png"), + + /** + * 省外线路 + */ + provinceOutLine("省外线路", 1, TheRapyRecuperationProvinceType.provinceOut.getValue(), "/assets/staffbenefit/therapyRecuperation/img/out.png"), + + /** + * 省内旅行社 + */ + provinceInTravelAgency("自由组团", 2, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png"), + + /** + * 酒店 + */ + provinceInHotel("目的地疗休养", 3, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png"); + + /** + * 学校自由组织 + */ +// schoolFree("学校自由报名", 3, TheRapyRecuperationProvinceType.provinceIn.getValue(), "/assets/staffbenefit/therapyRecuperation/img/lxs.png"); + + private final String label; + private final int value; + private final String regionType; + /** + * 缓存状态map k->value v->TheRapyRecuperationProvinceType.value + */ + public static Map typeMap = new HashMap<>(); + + /** + * 缓存状态map k->value v->TheRapyRecuperationProvinceType + */ + public static Map objMap = new HashMap<>(); + + static { + TheRapyRecuperationType[] values = TheRapyRecuperationType.values(); + for (TheRapyRecuperationType t : values) { + typeMap.put(t.getValue(), t.getRegionType()); + objMap.put(t.getValue(), t); + } + } + + + private final String imgUrl; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyCommonController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyCommonController.java new file mode 100644 index 0000000..9d9f826 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyCommonController.java @@ -0,0 +1,149 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller; + +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.stp.StpUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.sys.enums.SysFileEngineTypeEnum; +import com.budwk.app.sys.models.*; +import com.budwk.app.sys.services.SysFileService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.*; +import org.nutz.dao.*; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.http.*; +import java.io.*; +import java.util.*; + +@IocBean +@At("/platform/staffTherapyRecuperation/common") +@Ok("json:full") +public class TherapyCommonController { + @Inject + private Dao dao; + @Inject + private SysFileService sysFileService; + + @At + @SaCheckLogin + public Result enumOptions(String enumName) throws ReflectiveOperationException { + if (!Set.of("TheRapyRecuperationType", "TheRapyRecuperationProvinceType", "TheRapyRecuperationSignUpMode", + "TheRapyRecuperationLineCreateMode").contains(enumName)) return Result.error("未知选项类型"); + Class type = Class.forName("com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant." + enumName); + List options = new ArrayList<>(); + for (Object value : type.getEnumConstants()) { + NutMap option = NutMap.NEW().addv("label", type.getMethod("getLabel").invoke(value)) + .addv("value", type.getMethod("getValue").invoke(value)); + if ("TheRapyRecuperationType".equals(enumName)) { + option.addv("imgUrl", type.getMethod("getImgUrl").invoke(value)); + option.addv("regionType", type.getMethod("getRegionType").invoke(value)); + } + options.add(option); + } + return Result.success(options); + } + + @At({"/unions", "/getUnion"}) + @SaCheckLogin + public Result unions(Boolean isPermission) { + Cnd cnd = Cnd.NEW().asc("unionname"); + if (Boolean.TRUE.equals(isPermission) && !TherapyContext.hasAnyRoles("sysadmin,A06")) { + cnd.and("id", "=", TherapyContext.getUnionId()); + } + return Result.success(dao.query(TherapyUnion.class, cnd)); + } + + @At({"/units", "/getUnit", "/unionUnits", "/getUnitsByUnions"}) + @SaCheckLogin + public Result units(String unionId, String unionid) { + String id = Strings.isBlank(unionId) ? unionid : unionId; + return Result.success(dao.query(Sys_unit.class, Cnd.NEW().andEX("unionId", "=", id).asc("location"))); + } + + @At + @SaCheckLogin + public Result dictOptions(String code) { + Sys_dict parent = dao.fetch(Sys_dict.class, Cnd.where("code", "=", code)); + return Result.success(parent == null ? Collections.emptyList() : dao.query(Sys_dict.class, + Cnd.where("parentId", "=", parent.getId()).and("disabled", "=", false).asc("location"))); + } + + @At + @SaCheckLogin + public Result getValue(String key) { + if (!Set.of("recuperationVersion", "staffTherapyRecuperationVersion").contains(key)) return Result.error("未知配置"); + Sys_config config = dao.fetch(Sys_config.class, "staffTherapyRecuperationVersion"); + return Result.success((Object) (config == null ? "zjnu" : config.getConfigValue())); + } + + @At + @SaCheckLogin + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + public Result uploadFile(TempFile file) { + if (file == null) return Result.error("请选择文件"); + String id = sysFileService.uploadReturnId(SysFileEngineTypeEnum.MINIO.getValue(), file); + Sys_file uploaded = sysFileService.fetch(id); + return Result.success(fileInfo(uploaded)); + } + + private NutMap fileInfo(Sys_file file) { + return NutMap.NEW().addv("id", file.getId()).addv("filename", file.getName()) + .addv("filepath", file.getDownloadPath()).addv("url", file.getDownloadPath()); + } + + @At + @SaCheckLogin + public Result fileInfo(String[] ids) { + List result = new ArrayList<>(); + if (ids != null) for (String id : ids) { + Sys_file file = sysFileService.fetch(id); + if (file != null) result.add(fileInfo(file)); + } + return Result.success(result); + } + + @At + @SaCheckLogin + @POST + public Result deleteFile(String id) { + Sys_file file = sysFileService.fetch(id); + if (file != null && !Objects.equals(file.getCreatedBy(), TherapyContext.getUserId()) + && !TherapyContext.hasAnyRoles("sysadmin,A06")) return Result.error("无权删除此文件"); + sysFileService.delete(Collections.singletonList(id)); + return Result.success(); + } + + @At({"/preview", "/download"}) + @SaCheckLogin + @Ok("void") + public void preview(String id, HttpServletRequest request, HttpServletResponse response) throws IOException { + if (id != null && id.startsWith("/platform/sys/file/download?id=")) { + id = id.substring(id.indexOf("?id=") + 4); + } + sysFileService.download(id, request, response); + } + + @At + @SaCheckLogin + @Ok("void") + public void downloadTemplate(String filePath, String fileName, HttpServletResponse response) throws IOException { + String name = filePath == null ? "" : filePath.substring(filePath.lastIndexOf('/') + 1); + if (!Set.of("TravelAgencyImport.xlsx", "TravelEnrollImport.xlsx").contains(name)) { + response.sendError(404); + return; + } + try (InputStream in = getClass().getResourceAsStream("/static/assets/staffbenefit/therapyRecuperation/templates/" + name)) { + if (in == null) { + response.sendError(404); + return; + } + TherapyDownload.excelResponse(response, Strings.isBlank(fileName) ? name : fileName); + in.transferTo(response.getOutputStream()); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyWorkspaceController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyWorkspaceController.java new file mode 100644 index 0000000..4889b96 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/TherapyWorkspaceController.java @@ -0,0 +1,32 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller; + +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.stp.StpUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.TherapyRecuperationModule; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.*; +import javax.servlet.http.HttpServletRequest; + +@IocBean +@At("/platform/staffTherapyRecuperation") +public class TherapyWorkspaceController { + @At("") + @SaCheckLogin + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/index.html") + public void index(String screen, HttpServletRequest request) { + String url = TherapyRecuperationModule.ROOT + "/mobile/index"; + if (screen != null && !"signup".equals(screen)) { + boolean found = false; + for (String[] candidate : TherapyRecuperationModule.SCREENS) { + if (candidate[0].equals(screen)) { + StpUtil.checkPermission("staffTherapyRecuperation." + candidate[3]); + url = TherapyRecuperationModule.ROOT + candidate[2]; + found = true; + break; + } + } + if (!found) throw new IllegalArgumentException("未知的职工疗休养页面"); + } + request.setAttribute("therapyPageUrl", url); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationAuditController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationAuditController.java new file mode 100644 index 0000000..ecb97b3 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationAuditController.java @@ -0,0 +1,617 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit; + + +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAuditState; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.trans.Trans; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +@IocBean +@At("/platform/staffTherapyRecuperation/TheRapyAudit") +@Ok("json:full") +public class TheRapyRecuperationAuditController { + + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyAudit") + public void index() { + } + + @Inject + private TherapyContext vi; + + @Inject + private TheRapyRecuperationAuditService auditService; + + @Inject + private Dao dao; + + @Inject + private TherapyMessage msgApi; + + @At + @ViReturn + @SaCheckLogin + public Object getXlByUnion(Integer state, String unionId, String regionalNature, String year, String endYear, Integer signUpMode, String agencyId) { + + List xlByUnion = auditService.getXlByUnion(state, unionId, regionalNature, year, endYear, signUpMode, agencyId); + + return xlByUnion; + } + + + @At + @ViReturn + @SaCheckLogin + public Object getXlByUnionAudit(String unionId, String regionalNature, String year, Integer signUpMode) { + Sql sql = Sqls.create(""" + SELECT + line.id, + line.lineName, + line.regionalNature, + ts.id as selectId, + ts.playStartTime, + ts.playEndTime + FROM + staff_therapy_line_union_select ts + LEFT JOIN staff_therapy_line line ON line.id = ts.lineId + $condition + """); + Cnd cnd = Cnd.NEW(); + if (TherapyContext.hasAnyRoles("sysadmin,A06")) { + cnd.andEX("ts.unionId", "=", unionId); + } else { + cnd.and("ts.unionId", "=", vi.getUnionId()); + } + cnd.andEX("YEAR(ts.selectTime)", "=", year); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("line.signUpMode", "=", signUpMode); + cnd.groupBy("line.id"); + sql.setCondition(cnd); + return auditService.listMap(sql); + } + + + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyAudit") + public Object pageData(PageForm pageForm, String year, String unionId, + String unitId, String state, String takePartInLineId, + String isAudit, String regionalNature, String lotId, + String selectId) { + Sql sql = Sqls.create(""" + SELECT + enroll.*, + lineu.lineId, + line.lineName, + line.regionalNature, + '教职工' userNature, + state.stateColor, + state.stateName, + CONCAT(DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日')) AS linePlayTime, + IF + ( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) num + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd.andEX("enroll.selfUnionId", "=", unionId); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("lineu.lineId", "=", takePartInLineId); + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("lineu.signUpMode", "=", 1); + cnd.andEX("lineu.id", "=", selectId); + if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) { + cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword()); + } + if (Strings.isNotBlank(state)) { + if (state.equals("1")) { + cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } else if (state.equals("2")) { + cnd.andEX("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId()); + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } else if (state.equals("3")) { + cnd.andEX("enroll.selfUnionId", "!=", TherapyContext.getUnionId()); + cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } + } + if (Strings.isNotBlank(isAudit)) { + if (isAudit.equals("true")) { + if (state.equals("2") || state.equals("1")) { + cnd.and(new Static(""" + (( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s ) AND enroll.selfUnionId = '%s' ) + """.formatted(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNIT, TheRapyRecuperationState.PASS, vi.getUnionId()))); + } else if (state.equals("3")) { + cnd.and(new Static(""" + ((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s') + """.formatted(TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId()))); + } else { + /*cnd.and(new Static(""" + ((( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s ) AND enroll.selfUnionId = '%s' ) + OR + ((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s')) + """.formatted(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNIT, TheRapyRecuperationState.PASS, vi.getUnionId(), TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId())));*/ + cnd.and(new Static(""" + ((enroll.stateId = %s OR enroll.stateId=%s )AND enroll.takePartInUnionId='%s') + """.formatted(TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.PASS, vi.getUnionId()))); + } + } else { + cnd.and(new Static(""" + ((enroll.stateId = %s AND enroll.selfUnionId='%s')OR (enroll.stateId = %s AND enroll.takePartInUnionId='%s')) + """.formatted(TheRapyRecuperationState.UNIT, vi.getUnionId(), TheRapyRecuperationState.LINEUNIT, vi.getUnionId()))); + } + } else { + //屏蔽了本工会选择其他工会线路的人员 +// cnd.and(Cnd.exps("enroll.selfUnionId", "=", vi.getUnionId()).or("enroll.takePartInUnionId", "=", vi.getUnionId())); + cnd.and("enroll.takePartInUnionId", "=", vi.getUnionId()); + } + + + cnd.desc("enroll.signingUptime"); + cnd.desc("enroll.unitName"); + +// cnd.having(Cnd.where("isTransferIn","=",0)); + sql.setCondition(cnd); + + return auditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + + } + + + @At + @ViReturn + @SaCheckLogin + public Object findOne(String id) { + NutMap one = auditService.findOne(id); + return one; + } + + /** + * 单个审核 + * + * @param id + * @param flag + * @param isTransferIn + * @param auditOpinion + * @return + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyAudit") + public Object doAudit(String id, boolean flag, Boolean adjustment, boolean isTransferIn, String auditOpinion) { + Trans.exec(() -> { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = auditService.insert(audit); + if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) { + enroll.setSelfUnionAuditId(insert.getId()); + } else { + enroll.setJoinLineUnionAuditId(insert.getId()); + } + //如果通过 + if (flag) { + //如果参加的线路分工会是自己分工会的,并且状态等于分工会审核 + if (enroll.getTakePartInUnionId().equals(TherapyContext.getUnionId()) && enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) { + enroll.setStateId(TheRapyRecuperationState.PASS); + } else { + //否则就是不是参加的自己分工会线路,就需要线路分工会审核 + if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) { + enroll.setStateId(TheRapyRecuperationState.LINEUNIT); + } else { + enroll.setStateId(TheRapyRecuperationState.PASS); + } + } + } else { + if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT)) { + enroll.setStateId(TheRapyRecuperationState.UNITFAIL); + } else { + enroll.setStateId(TheRapyRecuperationState.LINEUNITFAIL); + } + } + + auditService.updateIgnoreNull(enroll); + auditMsg(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId()); + if (adjustment) { +// enroll.setNormal(false); + auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "=", enroll.getId())); + } + }); + return null; + } + + /** + * 撤回 + * + * @param id + * @return + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyAudit") + public Object doRecall(String id) { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + TheRapyRecuperationLineUnionSelect unionSelect = auditService.dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", enroll.getTakePartInLineId())); + if (enroll.getStateId().equals(TheRapyRecuperationState.UNITFAIL)) { + enroll.setStateId(TheRapyRecuperationState.UNIT); + enroll.setSelfUnionAuditId(null); + } else if (enroll.getStateId().equals(TheRapyRecuperationState.LINEUNIT)) { + enroll.setStateId(TheRapyRecuperationState.UNIT); + enroll.setSelfUnionAuditId(null); + } else if (enroll.getStateId().equals(TheRapyRecuperationState.LINEUNITFAIL)) { + enroll.setStateId(TheRapyRecuperationState.LINEUNIT); + enroll.setSelfUnionAuditId(null); +// } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getSelfUnionId().equals(vi.getUnionId())) { + } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getSelfUnionId().equals(unionSelect.getUnionId())) { + enroll.setStateId(TheRapyRecuperationState.UNIT); + enroll.setSelfUnionAuditId(null); +// } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getTakePartInUnionId().equals(vi.getUnionId())) { + } else if (enroll.getStateId().equals(TheRapyRecuperationState.PASS) && enroll.getTakePartInUnionId().equals(unionSelect.getUnionId())) { + enroll.setStateId(TheRapyRecuperationState.LINEUNIT); + enroll.setJoinLineUnionAuditId(null); + } + auditService.update(enroll); + + return null; + } + + /** + * 批量审核 + * + * @param ids + * @param auditOpinion + * @param flag + * @return + */ + @At + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission("staffTherapyRecuperation.TheRapyAudit") + public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) { + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = auditService.insert(audit); + List enrollIdList = new ArrayList<>(); + for (String id : ids) { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + //如果状态等于分工会审核,并且参加的线路分工会也是自己的工会,就代表自己参加自己的工会线路 + if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT) && enroll.getTakePartInUnionId().equals(vi.getUnionId())) { + enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL); + enroll.setSelfUnionAuditId(insert.getId()); + //如果状态等于分工会审核,并且参加的线路分工会不是自己的工会,就代表参加的不是自己工会的线路,就需要线路分工会审核 + } else if (enroll.getStateId().equals(TheRapyRecuperationState.UNIT) && !enroll.getTakePartInUnionId().equals(vi.getUnionId())) { + enroll.setStateId(flag ? TheRapyRecuperationState.LINEUNIT : TheRapyRecuperationState.UNITFAIL); + enroll.setSelfUnionAuditId(insert.getId()); + } else { + enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.LINEUNITFAIL); + enroll.setJoinLineUnionAuditId(insert.getId()); + } + if (adjustment) { +// enroll.setNormal(false); + enrollIdList.add(id); + } + auditService.updateIgnoreNull(enroll); + auditMsg(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId()); + } + auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList)); + return null; + } + + /** + * 审核发短信 + * + * @param stateId + * @param loginName + * @param takePartInLineId + */ + private void auditMsg(Integer stateId, String loginName, Boolean adjustment, String takePartInLineId) { + TherapyUser user = auditService.dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName)); + TheRapyRecuperationLineUnionSelect unionSelect = auditService.dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", takePartInLineId)); + TheRapyRecuperationLine theRapyRecuperationLine = auditService.dao().fetch(TheRapyRecuperationLine.class, Cnd.where("id", "=", unionSelect.getLineId())); + TherapyAuditState auditState = auditService.dao().fetch(TherapyAuditState.class, Cnd.where("stateId", "=", stateId)); + + String content = "【智慧工会】%s老师您好,您报名的%s线路因报名人数不足已取消,请尽快进入智慧工会重新选择线路。" + .formatted(user.getUsername(), theRapyRecuperationLine.getLineName()); + + List list = List.of(Map.of("type", "User", "userId", user.getLoginname(), "name", user.getUsername())); + if (stateId.equals(TheRapyRecuperationState.PASS)) { + content = "【智慧工会】%s老师您好,您报名的%s线路已组团成功,请按约定出行。" + .formatted(user.getUsername(), theRapyRecuperationLine.getLineName()); + + } + //msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", MsgApi.sendMode.normal.name()); + } + + + /** + * 查询报名人员的工会有哪些,并分组 + * + * @return + */ + @At + @ViReturn + @SaCheckLogin + public Object getBmUserUnion() { + Sql sql = Sqls.create(""" + SELECT + unionName unionname, + selfUnionId id + FROM + `staff_therapy_enroll` + $condition + """); + Cnd cnd = Cnd.NEW(); + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + cnd.and("takePartInLineId", "IS NOT", null); + cnd.and("takePartInLineId", "!=", ""); + cnd.and(Cnd.exps("takePartInUnionId", "=", vi.getUnionId()).or("selfUnionId", "=", vi.getUnionId())); + //cnd.and("selfUnionId", "=", vi.getUnionId()); + } + cnd.groupBy("selfUnionId"); + sql.setCondition(cnd); + + List unionList = auditService.listMap(sql); + + return unionList; + } + + /** + * 查询报名数量 + * + * @return + */ + @At + @ViReturn + @SaCheckLogin + public Object getApplyNumAudit(String takePartInLineId, String mode, String isAudit, Integer year, String selectId) { + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + String unionId = TherapyContext.getUnionId(); + Sql sql = Sqls.create(""" + SELECT + COUNT(1) as signUpNum, + $val as familyNumber + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + $condition + """); + String val = ""; + if (config.getFamilyInfo() == 1) { + val = "IFNULL(sum(familyNumber),0)"; + } else { + val = "IFNULL((select count(1) from staff_therapy_enroll_companion where trreId = enroll.id),0)"; + } + sql.setVar("val", val); + Sql sql2 = sql; + Sql sql3 = sql; + Sql sql4 = sql; + + if (StrUtil.isBlank(isAudit)) { + //本公会人员(自己线路) + Cnd cnd1 = Cnd.NEW(); + cnd1.andEX("takePartInUnionId", "=", unionId) + .and("selfUnionId", "=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .andEX("signUpMode", "=", 1) + .andEX("lineu.id", "=", selectId); + if (StrUtil.isNotBlank(mode)) { + cnd1.and("stateId", "=", TheRapyRecuperationState.PASS); + } + sql.setCondition(cnd1); + NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0))); + + //本工会人员(其他路线) + Cnd cnd2 = Cnd.NEW(); + cnd2.and("takePartInUnionId", "!=", unionId) + .and("selfUnionId", "=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .andEX("signUpMode", "=", 1) + .andEX("lineu.id", "=", selectId); + if (StrUtil.isNotBlank(mode)) { + cnd2.and("stateId", "=", TheRapyRecuperationState.PASS); + } + sql2.setCondition(cnd2); + NutMap map2 = (NutMap) Daos.query(dao, sql2.toString(), Sqls.callback.map()); + int count2 = Integer.parseInt(String.valueOf(map2.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map2.getOrDefault("familyNumber", 0))); + + //其他工会人员(选我线路) + Cnd cnd3 = Cnd.NEW(); + cnd3.and("takePartInUnionId", "=", unionId) + .and("selfUnionId", "!=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .andEX("signUpMode", "=", 1) + .andEX("lineu.id", "=", selectId); + if (StrUtil.isNotBlank(mode)) { + cnd3.and("stateId", "=", TheRapyRecuperationState.PASS); + } + sql3.setCondition(cnd3); + NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map()); + int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0))); + + //选择校工会线路人员 + Cnd cnd4 = Cnd.NEW(); + cnd4.and("selfUnionId", "=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .andEX("signUpMode", "=", 2) + .andEX("lineu.id", "=", selectId); + if (StrUtil.isNotBlank(mode)) { + cnd4.and("stateId", "=", TheRapyRecuperationState.PASS); + } + sql4.setCondition(cnd4); + NutMap map4 = (NutMap) Daos.query(dao, sql4.toString(), Sqls.callback.map()); + int count4 = Integer.parseInt(String.valueOf(map4.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map4.getOrDefault("familyNumber", 0))); + + return Map.of("count1", count1, "count2", count2, "count3", count3, "count4", count4); + } + + if ("true".equals(isAudit)) { + //本公会人员(自己线路) + Cnd cnd1 = Cnd.NEW(); + cnd1.and("takePartInUnionId", "=", unionId) + .and("selfUnionId", "=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .and("stateId", ">", TheRapyRecuperationState.UNIT) + .andEX("signUpMode", "=", 1); + sql.setCondition(cnd1); + NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0))); + + + //本工会人员(其他路线) +// Cnd cnd2 = Cnd.NEW(); +// cnd2.and("takePartInUnionId", "!=", unionId) +// .and("selfUnionId", "=", unionId) +// .and("isNormal", "=", true) +// .and("takePartInLineId", "is not", null) +// .andEX("YEAR(signingUptime)", "=", year) +// .and("stateId", ">", TheRapyRecuperationState.UNIT) +// .andEX("signUpMode", "=", 1); +// sql2.setCondition(cnd2); +// int count2 = auditService.count(sql2); + + //其他工会人员(选我线路) + Cnd cnd3 = Cnd.NEW(); + cnd3.and("takePartInUnionId", "=", unionId) + .and("selfUnionId", "!=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .and("stateId", ">", TheRapyRecuperationState.LINEUNIT) + .andEX("signUpMode", "=", 1); + sql3.setCondition(cnd3); + NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map()); + int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0))); + + +// return Map.of("count1", count1, "count2", count2, "count3", count3); + return Map.of("count1", count1, "count3", count3); + } + + if ("false".equals(isAudit)) { + //本公会人员(自己线路) + Cnd cnd1 = Cnd.NEW(); + cnd1.and("takePartInUnionId", "=", unionId) + .and("selfUnionId", "=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .and("stateId", "=", TheRapyRecuperationState.UNIT) + .andEX("signUpMode", "=", 1); + sql.setCondition(cnd1); + NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber", 0))); + + + //本工会人员(其他路线) +// Cnd cnd2 = Cnd.NEW(); +// cnd2.and("takePartInUnionId", "!=", unionId) +// .and("selfUnionId", "=", unionId) +// .and("isNormal", "=", true) +// .and("takePartInLineId", "is not", null) +// .andEX("YEAR(signingUptime)", "=", year) +// .and("stateId", "=", TheRapyRecuperationState.UNIT) +// .andEX("signUpMode", "=", 1); +// sql2.setCondition(cnd2); +// int count2 = auditService.count(sql2); + + //其他工会人员(选我线路) + Cnd cnd3 = Cnd.NEW(); + cnd3.and("takePartInUnionId", "=", unionId) + .and("selfUnionId", "!=", unionId) + .and("isNormal", "=", true) + .and("takePartInLineId", "is not", null) + .andEX("lineu.lineId", "=", takePartInLineId) + .andEX("YEAR(signingUptime)", "=", year) + .and("stateId", "=", TheRapyRecuperationState.LINEUNIT) + .andEX("signUpMode", "=", 1); + sql3.setCondition(cnd3); + NutMap map3 = (NutMap) Daos.query(dao, sql3.toString(), Sqls.callback.map()); + int count3 = Integer.parseInt(String.valueOf(map3.getOrDefault("signUpNum", 0))) + Integer.parseInt(String.valueOf(map3.getOrDefault("familyNumber", 0))); + +// return Map.of("count1", count1, "count2", count2, "count3", count3); + return Map.of("count1", count1, "count3", count3); + + + } + + return null; + } + + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationTravelAuditController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationTravelAuditController.java new file mode 100644 index 0000000..d008368 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationTravelAuditController.java @@ -0,0 +1,237 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit; + +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; +import org.nutz.trans.Trans; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @version 1.0 + * @Author zzr + * @name:TheRapyRecuperationTranlAuditController + * @Date 2024/5/22 9:59 + * @注释 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/TheRapyTravelAudit") +@Ok("json:full") +public class TheRapyRecuperationTravelAuditController { + + @Inject + private TheRapyRecuperationAuditService theRapyRecuperationAuditService; + + @Inject + private TherapyContext vi; + + @Inject + private Dao dao; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyTravelAudit") + public void index() { + } + + + @At + @ViReturn + public Object pageData(PageForm pageForm, + @Param(value = "agencyId", required = false) String agencyId, + @Param(value = "year", required = false) String year, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "unitId", required = false) String unitId, + @Param(value = "isAudit", required = false) String isAudit){ + Sql sql = Sqls.create(""" + SELECT + enroll.*, + state.stateColor, + state.stateName, + ta.travelAgencyName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + left join staff_therapy_travel_agency ta on ta.id = enroll.takePartInTravelAgencyId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd.and("enroll.selfUnionId", "=", StrUtil.isBlank(unionId) ? TherapyContext.getUnionId() : unionId); + cnd.and("enroll.takePartInTravelAgencyId", "is not", null); + cnd.and("enroll.takePartInTravelAgencyId", "!=", ""); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + if (isAudit.equals("true")) { + cnd.and("enroll.stateId", ">", TheRapyRecuperationState.UNIT); + } else if (isAudit.equals("false")){ + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.UNIT); + } + + if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) { + cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword()); + } + + cnd.desc("enroll.signingUptime"); + cnd.desc("enroll.unitName"); + + sql.setCondition(cnd); + + return theRapyRecuperationAuditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @At + @ViReturn + @SaCheckLogin + public Object getBmUserUnion() { + Sql sql = Sqls.create(""" + SELECT + unionName unionname, + selfUnionId id + FROM + `staff_therapy_enroll` + $condition + """); + Cnd cnd = Cnd.NEW(); + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + cnd.and("takePartInTravelAgencyId", "IS NOT", null); + cnd.and("takePartInTravelAgencyId", "!=", ""); + cnd.and("selfUnionId", "=", vi.getUnionId()); + } + cnd.groupBy("selfUnionId"); + sql.setCondition(cnd); + List unionList = theRapyRecuperationAuditService.listMap(sql); + return unionList; + } + + @At + @ViReturn + @SaCheckLogin + public Object getApplyNumAudit(String agencyId, String isAudit, Integer year) { + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + String unionId = TherapyContext.getUnionId(); + Sql sql = Sqls.create(""" + SELECT + count(1) as signUpNum, + $val as familyNumber + FROM + `staff_therapy_enroll` enroll + $condition + """); + String val = ""; + if(config.getFamilyInfo() == 1) { + val = "IFNULL(sum(familyNumber),0)"; + } else { + val = "IFNULL((select count(1) from staff_therapy_enroll_companion where trreId = enroll.id),0)"; + } + sql.setVar("val", val); + Cnd cnd = Cnd.NEW(); + if (isAudit.equals("true")) { + cnd.and("enroll.stateId", ">", TheRapyRecuperationState.UNIT); + } else if (isAudit.equals("false")){ + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.UNIT); + } + cnd.andEX("takePartInTravelAgencyId", "=", agencyId); + cnd.andEX("year(signingUptime)", "=", year); + cnd.and("takePartInTravelAgencyId", "is not", null); + cnd.and("takePartInTravelAgencyId", "!=", ""); + cnd.and("selfUnionId", "=", unionId); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + sql.setCondition(cnd); + NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + int count1 = Integer.parseInt(String.valueOf(map.getOrDefault("signUpNum",0))) + + Integer.parseInt(String.valueOf(map.getOrDefault("familyNumber",0))); + return Map.of("count1", count1); + } + + @At + @ViReturn + @SaCheckLogin + public Object doAudit(String id, boolean flag,Boolean adjustment, String auditOpinion) { + Trans.exec(() -> { + TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id); + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = dao.insert(audit); + enroll.setSelfUnionAuditId(insert.getId()); + enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL); + dao.updateIgnoreNull(enroll); +// auditMsg(enroll.getStateId(), enroll.getLoginName(),adjustment, enroll.getTakePartInLineId()); + if (adjustment){ +// enroll.setNormal(false); + dao.clear(TheRapyRecuperationEnroll.class,Cnd.where("id","=",enroll.getId())); + } + }); + return null; + } + + @At + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) { + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = dao.insert(audit); + List enrollIdList = new ArrayList<>(); + for (String id : ids) { + TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id); + enroll.setSelfUnionAuditId(insert.getId()); + enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.UNITFAIL); + dao.updateIgnoreNull(enroll); + //auditMsg(enroll.getStateId(), enroll.getLoginName(),adjustment, enroll.getTakePartInLineId()); + } + dao.clear(TheRapyRecuperationEnroll.class,Cnd.where("id","in",enrollIdList)); + return null; + } + + @At + @ViReturn + @SaCheckLogin + public Object doRecall(String id) { + TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, id); + enroll.setStateId(TheRapyRecuperationState.UNIT); + enroll.setSelfUnionAuditId(null); + dao.update(enroll); + return null; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationXghAuditController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationXghAuditController.java new file mode 100644 index 0000000..6501526 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/audit/TheRapyRecuperationXghAuditController.java @@ -0,0 +1,355 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.audit; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; +import org.nutz.trans.Trans; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +@IocBean +@At("/platform/staffTherapyRecuperation/TheRapyXghAudit") +@Ok("json:full") +public class TheRapyRecuperationXghAuditController { + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public void index() { + } + + @Inject + private TherapyContext vi; + + @Inject + private TheRapyRecuperationAuditService auditService; + + @Inject + private Dao dao; + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + + @Inject("refer:staffTherapyDataService") + private TherapyService viService; + + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object pageData(PageForm pageForm, String year, String unionId, + String unitId, String state, String takePartInLineId, + String isAudit, String regionalNature, String lotId, + String selectId) { + Sql sql = Sqls.create(""" + SELECT + enroll.*, + line.lineName, + line.id as lineId, + line.regionalNature, + '教职工' userNature, + state.stateColor, + state.stateName, + CONCAT(DATE_FORMAT(rs.playStartTime,'%m月%d日'),'-',DATE_FORMAT(rs.playEndTime,'%m月%d日')) AS linePlayTime, + IF + ( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) num + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_line_union_select` rs ON rs.id = enroll.takePartInLineId + LEFT JOIN `staff_therapy_line` line on line.id=rs.lineId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd.andEX("enroll.selfUnionId", "=", unionId); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("rs.signUpMode", "=", "2"); + cnd.andEX("rs.id", "=", selectId); + if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) { + cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword()); + } + if (Strings.isNotBlank(isAudit)) { + if (isAudit.equals("true")) { + cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.PASS))); + } else { + cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.SCHOOL))); + } + } else { + cnd.and(new Static("( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s)". + formatted(TheRapyRecuperationState.SCHOOL, TheRapyRecuperationState.SCHOOLFAIL, TheRapyRecuperationState.PASS))); + } + cnd.desc("enroll.signingUptime"); + cnd.desc("enroll.unitName"); + sql.setCondition(cnd); + return auditService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object getLineNumber(PageForm pageForm, String year, String unionId, + String unitId, String state, String takePartInLineId, + String isAudit, String regionalNature, String lotId, String selectId) { + Sql sql = Sqls.create(""" + SELECT + enroll.*, + line.lineName, + line.id as lineId, + line.regionalNature, + '教职工' userNature, + state.stateColor, + state.stateName, + IF + ( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) num + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_line_union_select` rs ON rs.id = enroll.takePartInLineId + LEFT JOIN `staff_therapy_line` line on line.id=rs.lineId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd.andEX("enroll.selfUnionId", "=", unionId); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("rs.signUpMode", "=", "2"); + cnd.andEX("rs.id", "=", selectId); + if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) { + cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword()); + } + if (Strings.isNotBlank(isAudit)) { + if (isAudit.equals("true")) { + cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.PASS))); + } else { + cnd.and(new Static("enroll.stateId = %s".formatted(TheRapyRecuperationState.SCHOOL))); + } + } else { + cnd.and(new Static("( enroll.stateId = %s OR enroll.stateId = %s OR enroll.stateId = %s)". + formatted(TheRapyRecuperationState.SCHOOL, TheRapyRecuperationState.SCHOOLFAIL, TheRapyRecuperationState.PASS))); + } + cnd.desc("enroll.signingUptime"); + cnd.desc("enroll.unitName"); + sql.setCondition(cnd); + List nutMaps = auditService.listMap(sql); + int familyNumber = nutMaps.stream().filter(o -> StrUtil.isNotBlank(o.getString("familyNumber"))).mapToInt(o -> o.getInt("familyNumber")).sum(); + return familyNumber + nutMaps.size(); + } + + + /** + * 单个审核 + * + * @param id + * @param flag + * @param isTransferIn + * @param auditOpinion + * @return + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object doAudit(String id, boolean flag, boolean isTransferIn, String auditOpinion, Boolean adjustment) { + Trans.exec(() -> { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = auditService.insert(audit); + enroll.setSchoolUnionAuditId(insert.getId()); + //如果通过 + if (flag) { + enroll.setStateId(TheRapyRecuperationState.PASS); + } else {//审核不通过 + enroll.setStateId(TheRapyRecuperationState.SCHOOLFAIL); + } + auditService.updateIgnoreNull(enroll); + auditService.schoolAudit(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId()); + if (adjustment) { +// enroll.setNormal(false); + auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "=", enroll.getId())); + } + }); + return null; + } + + /** + * 撤回 + * + * @param id + * @return + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object doRecall(String id) { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + enroll.setStateId(TheRapyRecuperationState.SCHOOL); + enroll.setSchoolUnionAuditId(null); + auditService.update(enroll); + return null; + } + + /** + * 批量审核 + * + * @param ids + * @param auditOpinion + * @param flag + * @return + */ + @At + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object doOnekeyAudit(String[] ids, String auditOpinion, boolean flag, Boolean adjustment) { + TherapyAudit audit = new TherapyAudit(); + audit.setAuditOpinion(auditOpinion); + audit.setAuditor(TherapyContext.getUserId()); + audit.setLoginname((String) TherapyContext.getPrincipalProperty("loginname")); + audit.setUsername((String) TherapyContext.getPrincipalProperty("username")); + audit.setAuditTime(new Date()); + audit.setAuditPass(flag); + TherapyAudit insert = auditService.insert(audit); + //List enrollList = auditService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", ids)); + List enrollIdList = new ArrayList<>(); + for (String id : ids) { + TheRapyRecuperationEnroll enroll = auditService.dao().fetch(TheRapyRecuperationEnroll.class, id); + enroll.setStateId(flag ? TheRapyRecuperationState.PASS : TheRapyRecuperationState.SCHOOLFAIL); + enroll.setSchoolUnionAuditId(insert.getId()); + auditService.updateIgnoreNull(enroll); + auditService.schoolAudit(enroll.getStateId(), enroll.getLoginName(), adjustment, enroll.getTakePartInLineId()); + if (adjustment) { +// enroll.setNormal(false); + enrollIdList.add(id); + } + } + auditService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList)); + return null; + } + + + /** + * 校工会选择线路查询 + * + * @return + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyXghAudit") + public Object getXghLine() { + Sql sql = Sqls.create(""" + SELECT + line.*, + un.unionname + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_union un ON un.id = enroll.takePartInUnionId + where line.signUpMode='2' and line.createMode='2' + group by line.id + """); + return baseService.listMap(sql); + } + + @At + @ViReturn + @SaCheckLogin + public Object getLinePlayTimeByLineId(String lineId, + @Param(value = "signUpMode",required = false) Integer signUpMode, + @Param(value = "year",required = false) Integer year, + @Param(value = "startYear",required = false)Integer startYear, + @Param(value = "endYear",required = false)Integer endYear, + @Param(value = "flag",required = false) Boolean flag) { + Cnd cnd = Cnd.NEW(); + cnd.and("lineId", "=", lineId); + if (flag == null || !flag){ + cnd.andEX("signUpMode", "=", signUpMode); + cnd.and("YEAR(selectTime)", "=", year); + } else { + cnd.and("YEAR(selectTime)", ">=", startYear); + cnd.and("YEAR(selectTime)", "<=", endYear); + } + List query = dao.query(TheRapyRecuperationLineUnionSelect.class, cnd); + //.and("selectUserId", "=", ShiroUtil.getUserId()).and("unionId", "=", Vi.getUnionId())); + + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + List nutMaps = new ArrayList<>(); + query.forEach(v -> { + String startTime = DateUtil.formatChineseDate(v.getPlayStartTime(), false, false).substring(5); + String endTime = DateUtil.formatChineseDate(v.getPlayEndTime(), false, false).substring(5); + NutMap map = new NutMap(); + + List enrollList = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", v.getId()) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL))); + + int hasSignNumber; + if (config.getFamilyInfo() == 1) { + int sum = enrollList.stream().mapToInt(TheRapyRecuperationEnroll::getFamilyNumber).sum(); + hasSignNumber = enrollList.size() + sum; + } else { + List list = enrollList.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList()); + List companions = dao.query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", list)); + hasSignNumber = enrollList.size() + companions.size(); + } + map.setv("times", startTime + "-" + endTime + "(报名人数:" + hasSignNumber + ",其中家属:" + (hasSignNumber - enrollList.size()) + "人)"); + map.setv("selectId", v.getId()); + nutMaps.add(map); + }); + return nutMaps; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java new file mode 100644 index 0000000..d3ab5ca --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/baseManage/TheRapyRecuperationBaseManagerController.java @@ -0,0 +1,360 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.baseManage; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.annotation.Excel; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.dao.CndPlus; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.baseManage.TheRapyRecuperationBaseManagerService; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.baseManage.TheBaseManagerController + * @Description: 疗休养基地管理 + * @Author zzr + * @Date 2023/6/5 + * @Version V1.0 + **/ + +@IocBean +@At("/platform/staffTherapyRecuperation/baseManagement") +@Ok("json:full") +public class TheRapyRecuperationBaseManagerController { + + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + @Inject + private Dao dao; + + @Inject + private TheRapyRecuperationBaseManagerService theRapyRecuperationBaseManagerService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html") + @SaCheckPermission("staffTherapyRecuperation.line") + public void index() { + } + + + /** + * 分页展示 + * + * @param pageForm 分页对象 + * @param year 查询参数 + * @param lotId 标段时间 + * @param baseName 基地名 + * @param unionId 分工会 + * @param travelAgencyId 旅行社 + * @param regionalNature 活动范围 + * @return {@link Object} + */ + @At + @POST + @Ok("json:full") + @ViReturn + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object pageData(PageForm pageForm, Integer year, String lotId, String baseName, String unionId, String travelAgencyId, String regionalNature) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + tb.id, + tb.sortNumber, + tb.baseName, + tb.regionalNature, + tb.year, + tb.isDisabled, + tb.lotId, + tb.createUnionId, + tb.signUpStartTime, + tb.signUpEndTime, + tb.changeEndTime, + tb.createMode, + tb.activityStartTime, + tb.activityEndTime, + tb.files, + tb.baseContactPerson, + tb.baseContactNumber, + tb.files AS fileId, + gh.unionname createUnionName, + u.username createUserName, + ta.travelAgencyName, + ta.contact, + ta.contactMobileNumber, + ta.officialWebsite + FROM + `staff_therapy_base_management` tb + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = tb.travelAgencyId + LEFT JOIN staff_therapy_union gh ON gh.id = tb.createUnionid + LEFT JOIN staff_therapy_user u ON u.id = tb.opBy + $condition + """); + cnd.where().andEX("tb.`year`", "=", year); + cnd.where().andEX("tb.lotId", "=", lotId); + cnd.and(Cnd.likeEX("tb.baseName", baseName)); + cnd.and(Cnd.likeEX("tb.travelAgencyId", travelAgencyId)); + cnd.and(Cnd.likeEX("tb.regionalNature", regionalNature)); + cnd.desc("tb.`year`"); + cnd.asc("tb.sortNumber"); + cnd.asc("tb.id"); + if (!TherapyContext.hasAnyRoles(List.of("sysadmin", "A06"))) { + if (TherapyContext.hasRole("H04")) { + cnd.and("tb.createUnionId", "=", TherapyContext.getUnionId()); + } + } else { + cnd.andEX("tb.createUnionId", "=", unionId); + } + sql.setCondition(cnd); + return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + + /** + * 是否启用基地线路 + * + * @param id 基地线路id + * @return {@link Object} + */ + @At("/openClosedBase/?") + @POST + @ViReturn + @SaCheckLogin + public Object openClosedBase(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + //位运算 取反 + dao.update(TheRapyRecuperationBaseManagement.class, Chain.makeSpecial("isDisabled", "isDisabled ^ 1"), Cnd.where("id", "=", id)); + return null; + } + + /** + * 查询一条基地线路 + * + * @param id + * @return + */ + @At("/selectBaseManageById/?") + @ViReturn + @SaCheckLogin + public Object selectBaseManageById(String id) { + Assert.notBlank(id); + return dao.fetchLinks(dao.fetch(TheRapyRecuperationBaseManagement.class, id), "travelAgency"); + } + + + /** + * 新增/修改 + * + * @param baseManagement 基地线路 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object doSubmit(@Param("base") TheRapyRecuperationBaseManagement baseManagement) { + baseManagement.setOpBy((String) TherapyContext.getPrincipalProperty("id")); + baseManagement.setCreateUnionId((String) TherapyContext.getPrincipalProperty("unionid")); + baseManagement.setOpAt(String.valueOf(new Date().getTime())); + dao.insertOrUpdate(baseManagement); + return null;//deleteBase + } + + /** + * 删除线路 + * + * @param id 线路id + * @return {@link Object} + */ + @At("/deleteBase/?") + @POST + @ViReturn + @SaCheckLogin + public Object deleteBase(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + dao.delete(TheRapyRecuperationBaseManagement.class, id); + return null; + } + + /** + * 查询所有酒店 + * + * @return {@link Object} + */ + @At("/listAllBase") + @POST + @ViReturn + @SaCheckLogin + public Object listAllBase(String startYear, String endYear, String year) { + Sql sql = Sqls.create("select * from `staff_therapy_base_management` tb left join `staff_therapy_lot` lot on lot.id=tb.lotId $condition"); + CndPlus cnd = new CndPlus(); + + cnd.andEX("tb.`year`", ">=", startYear); + cnd.andEX("tb.`year`", "<=", endYear); + cnd.andEX("tb.`year`", "=", year); + sql.setCondition(cnd); + return baseService.listMap(sql); + } + + /** + * 手机端酒店介绍所有信息 + * + * @param id id + * @return {@link Object} + */ + @At("/selectBaseAllInfo") + @GET + @ViReturn + @SaCheckLogin + public Object selectBaseAllInfo(@Param("id") String id) { + Assert.notBlank(id); + return theRapyRecuperationBaseManagerService.selectBaseAllInfo(id); + } + + + /** + * 目的地导入模版 + * + * @param response + */ + @At + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.TheBaseManagement") + public void exportTemplate(HttpServletResponse response) { + try { + //查旅行社,转数组 + List travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber")); + List excelTravelAgencyList = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList()); + String[] excelTravelAgencyArrs = excelTravelAgencyList.toArray(new String[excelTravelAgencyList.size()]); + + //查标段,转数组 + List lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id")); + List excelLotList = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList()); + String[] excelLotArrs = excelLotList.toArray(new String[excelLotList.size()]); + + TherapyDownload.excelResponse(response, "目的地导入模版.xls"); + Class excelModeClass = TheRapyRecuperationBaseManagement.class; + Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields(); + //字段过滤 + List needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature", "isDisabled", "createMode").contains(v.getName())).collect(Collectors.toList()); + for (Field field : needAddReplaceFields) { + Excel excelAnnotation = field.getAnnotation(Excel.class); + if (Lang.isNotEmpty(excelAnnotation)) { + InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation); + Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); + memberValues.setAccessible(true); + Map e = (Map) memberValues.get(invocationHandler); + e.put("addressList", true); + if (field.getName().equals("travelAgencyId")) { + e.put("replace", excelTravelAgencyArrs); + } else if (field.getName().equals("lotId")) { + e.put("replace", excelLotArrs); + } else if (field.getName().equals("regionalNature")) { + e.put("replace", new String[]{"省内_省内", "省外_省外"}); + } else if (field.getName().equals("createMode")) { + e.put("replace", new String[]{"校工会_1", "分工会_2"}); + } else if (field.getName().equals("isDisabled")) { + e.put("replace", new String[]{"是_1", "否_0"}); + } + } + } + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyRecuperationBaseManagement.class, new ArrayList<>()); + ServletOutputStream outputStream = response.getOutputStream(); + sheets.write(outputStream); + outputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * 目的地导入 + * + * @param file + * @return + */ + @At + @ViReturn + @SaCheckLogin + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @Aop(TransAop.READ_COMMITTED) + public Object importBaseManager(TempFile file) { + if (Lang.isEmpty(file)) { + return Result.error("上传的文件不能为空"); + } + String extName = FileUtil.extName(file.getFile()); + if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { + return Result.error("请上传xls,xlsx文件"); + } + List excelList; + try { + ImportParams importParams = new ImportParams(); + excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyRecuperationBaseManagement.class, importParams); + } catch (Exception e) { + e.printStackTrace(); + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + try { + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getBaseName())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) { + return Result.error("目的地名称和旅行社名称不能为空"); + } + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) { + return Result.error("时间标段和活动范围不能为空"); + } + excelList.forEach(v -> v.setOpBy((String) TherapyContext.getPrincipalProperty("id"))); + dao.insertOrUpdate(excelList); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java new file mode 100644 index 0000000..ef407f7 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationLineController.java @@ -0,0 +1,708 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.annotation.Excel; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.sys.models.Sys_user_source; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationLineCreateMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportImageMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyTravelLineExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFPatriarch; +import org.apache.poi.hssf.usermodel.HSSFPicture; +import org.apache.poi.hssf.usermodel.HSSFPictureData; +import org.apache.poi.hssf.usermodel.HSSFShape; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.DataFormat; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFDrawing; +import org.apache.poi.xssf.usermodel.XSSFPicture; +import org.apache.poi.xssf.usermodel.XSSFPictureData; +import org.apache.poi.xssf.usermodel.XSSFShape; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage.TheRapyRecuperationLineController + * @Description: 疗休养线路管理 + * @Author zxc + * @Date 2022/5/31:09:34 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/line") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationLineController { + + /** + * 新线路导入模板表头占用1行,图片锚点行号需减去表头行数后才能对应导入数据下标。 + */ + private static final int LINE_IMPORT_HEADER_ROWS = 1; + + /** + * 新线路导入模板中“联系方式”列下标,设置为文本格式避免手机号被Excel转成科学计数法。 + */ + private static final int LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX = 10; + + /** + * 新线路导入模板中“移动端缩略图”列下标,用于定位Excel内嵌图片。 + */ + private static final int LINE_IMPORT_THUMBNAIL_COLUMN_INDEX = 13; + + @Inject + private TheRapyRecuperationLineService lineService; + @Inject + private Dao dao; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html") + @SaCheckPermission("staffTherapyRecuperation.line") + public void index() { + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @return {@link Object} + */ + @At + @POST + @Ok("json:full") + @ViReturn + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object pageData(PageForm pageForm, Integer startYear , Integer endYear, String keywords, String travelAgencyId, String lineName, String unionId, String lotId, Integer signUpMode) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.`year`", ">=", startYear); + cnd.andEX("line.`year`", "<=", endYear); + cnd.andEX("line.travelAgencyId", "=", travelAgencyId); + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("line.signUpMode", "=", signUpMode); + cnd.and(Cnd.likeEX("line.lineName", lineName)); + + /*if (StrUtil.isNotBlank(keywords)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.orLike("line.lineName", keywords); + seg.orLike("line.travelAgencyName", keywords); + cnd.and(seg); + }*/ + if (!com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasAnyRoles(List.of("sysadmin", "A06"))) { + if (com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasRole("H04")) { + cnd.and("line.createUnionId", "=", TherapyContext.getUnionId()); + } + } else { + cnd.andEX("line.createUnionId", "=", unionId); + } + cnd.desc("line.year").asc("line.serialNumber"); + return lineService.pageData(pageForm, cnd); + } + + @At + @POST + @ViReturn + @SaCheckLogin + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object getNo() { + Object serialNumber = dao.func2(TheRapyRecuperationLine.class, "max", "serialNumber"); + serialNumber = Objects.requireNonNullElse(serialNumber, 0); + return Integer.parseInt(serialNumber.toString()) + 1; + } + + /** + * 提交 + * + * @param line 线路 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object doSubmit(TheRapyRecuperationLine line) { + if (StrUtil.isBlank(line.getId())) { + if (lineService.count(Cnd.where("serialNumber", "=", line.getSerialNumber())) > 0) { + return Result.error("编号已存在"); + } + lineService.addLine(line); + } else { + if (lineService.count(Cnd.where("serialNumber", "=", line.getSerialNumber()).and("id", "!=", line.getId())) > 0) { + return Result.error("编号已存在"); + } + lineService.editLine(line); + } + return null; + } + + /** + * 开启或关闭线路 + * + * @param id 线路id + * @return {@link Object} + */ + @At("/openClosedLine/?") + @POST + @ViReturn + @SaCheckLogin + public Object openClosedLine(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + lineService.openClosedLine(id); + return null; + } + + /** + * 删除线路 + * + * @param id 线路id + * @return {@link Object} + */ + @At("/deleteLine/?") + @POST + @ViReturn + @SaCheckLogin + public Object deleteLine(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + lineService.deleteLine(id); + return null; + } + + + /** + * 查询线路详细信息 + * + * @param id id + * @return {@link Object} + */ + @At("/selectLineInfoById/?") + @ViReturn + @SaCheckLogin + public Object selectLineInfoById(String id) { + Assert.notBlank(id); + return lineService.selectLineInfoById(id); + } + + + /** + * 根据分工会选择的线路id查询所该线路报名的人 + * + * @param pageForm 页面形式 + * @param id id + * @return {@link Object} + */ + @At("/selectLineUser") + @ViReturn + @SaCheckLogin + public Object selectLineUser(PageForm pageForm, String id, String unionId) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + return lineService.selectLineUser(pageForm, id, unionId); + } + + @At("/getCreateMode") + @ViReturn + @SaCheckLogin + public Object getCreateMode() { + boolean hasSchoolAdminRole = com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasAnyRoles(List.of("sysadmin", "A06")); + if (hasSchoolAdminRole) { + return TheRapyRecuperationLineCreateMode.SCHOOL.getValue(); + } + return TheRapyRecuperationLineCreateMode.UNION.getValue(); + } + + /** + * 查看各个分工会设置的时间信息 + * + * @param id 线路id + * @return {@link Object} + */ + @At("/viewUnionSelectTimeInfo/?") + @ViReturn + @SaCheckLogin + public Object viewUnionSelectTimeInfo(String id) { + Assert.notBlank(id); + return lineService.viewUnionSelectTimeInfo(id); + } + + /** + * 是否有权限 + * + * @return {@link Object} + */ + @At + @ViReturn + @SaCheckLogin + public Object hasAnyRoles(@Param("roles") String[] roles) { + boolean b = TherapyContext.hasAnyRoles(roles); + return b; + } + + /** + * 旅行社 + * + * @return {@link Object} + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.line") + public Object getTravelAgencyOptions(Integer year) { + List travelAgencies = lineService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().andEX("year","=",year).asc("serialNumber")); + return travelAgencies; + } + + + /** + * 线路导入 + * + * @param file + * @return + */ + @At + @ViReturn + @SaCheckLogin + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @Aop(TransAop.READ_COMMITTED) + public Object travelLineImport(TempFile file) { + if (Lang.isEmpty(file)) { + return Result.error("上传的文件不能为空"); + } + String extName = FileUtil.extName(file.getFile()); + if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { + return Result.error("请上传xls,xlsx文件"); + } + List excelList; + try { + ImportParams importParams = new ImportParams(); + excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelLineExcelMode.class, importParams); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + try { + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyId()))) { + return Result.error("旅行社名称不能为空"); + } + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getRegionalNature()))) { + return Result.error("时间标段和活动范围不能为空"); + } + List list = new ArrayList<>(); + for (TheRapyTravelLineExcelMode mode : excelList) { + TheRapyRecuperationLine line = new TheRapyRecuperationLine(); + line.setYear(mode.getYear()); + line.setSerialNumber(mode.getSerialNumber()); + line.setLineName(mode.getLineName()); + line.setTravelAgencyId(mode.getTravelAgencyId()); + line.setRegionalNature(mode.getRegionalNature()); + line.setContent(mode.getContent()); + line.setMinimumGroupSize(mode.getMinimumGroupSize()); + if (mode.getIsDisabled().equals("是")) { + line.setDisabled(false); + } else if (mode.getIsDisabled().equals("否")) { + line.setDisabled(true); + } + line.setEstimatedCost(mode.getEstimatedCost()); + line.setLotId(mode.getLotId()); +// line.setLineContact(mode.getLineContact()); +// line.setLineContactPhone(mode.getLineContactPhone()); + list.add(line); + } + dao.insert(list); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("导入失败"); + } + return null; + } + + + /** + * 线路导入模版 + * + * @param response + */ + /** + * 按线路管理页面字段导入线路。 + * + * @param file Excel文件 + * @return 导入结果 + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.line") + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @Aop(TransAop.READ_COMMITTED) + public Object importLineByPageFields(TempFile file) { + if (Lang.isEmpty(file)) { + return Result.error("上传的文件不能为空"); + } + String extName = FileUtil.extName(file.getFile()); + if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { + return Result.error("请上传xls,xlsx文件"); + } + + List excelList; + Map imageMap; + try { + ImportParams importParams = new ImportParams(); + excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyLineImportExcelMode.class, importParams); + fillLineImportContactPhone(excelList, file.getFile()); + imageMap = extractLineImportImages(file.getFile(), extName); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("读取不到数据,请检查excel文件格式"); + } + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + + try { + int count = lineService.importLineByPageFields(excelList, imageMap); + return Result.success("成功导入" + count + "条线路"); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + } + + /** + * 下载按线路管理页面字段生成的新线路导入模板。 + * + * @param response 响应对象 + */ + @At + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.line") + public void exportPageFieldsTemplate(HttpServletResponse response) { + try { + // 标段下拉复用页面配置接口返回的标段数据。 + List lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id")); + List excelLots = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList()); + + List needAddReplaceFields = Arrays.stream(TheRapyLineImportExcelMode.class.getDeclaredFields()) + .filter(v -> List.of("lotId", "regionalNature", "signUpMode", "isEnabled").contains(v.getName())) + .collect(Collectors.toList()); + for (Field field : needAddReplaceFields) { + Excel excelAnnotation = field.getAnnotation(Excel.class); + if (Lang.isEmpty(excelAnnotation)) { + continue; + } + InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation); + Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); + memberValues.setAccessible(true); + Map e = (Map) memberValues.get(invocationHandler); + e.put("addressList", true); + if (field.getName().equals("lotId")) { + e.put("replace", excelLots.toArray(new String[0])); + } else if (field.getName().equals("regionalNature")) { + e.put("replace", buildRegionalNatureExcelOptions()); + } else if (field.getName().equals("signUpMode")) { + e.put("replace", buildSignUpModeExcelOptions()); + } else if (field.getName().equals("isEnabled")) { + e.put("replace", new String[]{"是_是", "否_否"}); + } + } + + TherapyDownload.excelResponse(response, "线路导入模板.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyLineImportExcelMode.class, new ArrayList<>()); + applyLineImportTemplateCellStyle(sheets); + ServletOutputStream outputStream = response.getOutputStream(); + sheets.write(outputStream); + outputStream.close(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } + + /** + * 设置新线路导入模板的关键列格式。 + * + * @param workbook 导出的模板工作簿 + */ + private void applyLineImportTemplateCellStyle(Workbook workbook) { + Sheet sheet = workbook.getSheetAt(0); + DataFormat dataFormat = workbook.createDataFormat(); + CellStyle textStyle = workbook.createCellStyle(); + textStyle.setDataFormat(dataFormat.getFormat("@")); + + // 联系方式按字符串字段处理,模板层面先把整列设置为文本格式。 + sheet.setDefaultColumnStyle(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX, textStyle); + sheet.setColumnWidth(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX, 20 * 256); + sheet.setColumnWidth(LINE_IMPORT_THUMBNAIL_COLUMN_INDEX, 20 * 256); + } + + /** + * 按Excel显示文本重读“联系方式”列,确保长手机号等内容按字符串导入。 + * + * @param excelList EasyPoi读取出的导入数据 + * @param excelFile Excel文件 + * @throws Exception Excel读取失败时抛出异常 + */ + private void fillLineImportContactPhone(List excelList, File excelFile) throws Exception { + DataFormatter dataFormatter = new DataFormatter(); + try (InputStream inputStream = new FileInputStream(excelFile); + Workbook workbook = WorkbookFactory.create(inputStream)) { + Sheet sheet = workbook.getSheetAt(0); + for (int i = 0; i < excelList.size(); i++) { + Row row = sheet.getRow(i + LINE_IMPORT_HEADER_ROWS); + if (row == null) { + continue; + } + Cell cell = row.getCell(LINE_IMPORT_CONTACT_PHONE_COLUMN_INDEX); + if (cell == null) { + continue; + } + + // 使用DataFormatter读取用户看到的文本,避免联系方式被当作数值转成科学计数法。 + String phone = dataFormatter.formatCellValue(cell); + if (StrUtil.isNotBlank(phone)) { + excelList.get(i).setLineContactPhone(phone.trim()); + } + } + } + } + + /** + * 提取新线路导入模板“移动端缩略图”列中的内嵌图片。 + * + * @param excelFile Excel文件 + * @param extName 文件扩展名 + * @return key为导入数据行下标、value为图片内容的映射 + * @throws Exception Excel读取失败时抛出异常 + */ + private Map extractLineImportImages(File excelFile, String extName) throws Exception { + if ("xlsx".equalsIgnoreCase(extName)) { + return extractXlsxLineImportImages(excelFile); + } + return extractXlsLineImportImages(excelFile); + } + + /** + * 解析xlsx模板中的内嵌图片,按图片左上角锚点匹配到“移动端缩略图”列。 + * + * @param excelFile xlsx文件 + * @return 图片映射 + * @throws Exception Excel读取失败时抛出异常 + */ + private Map extractXlsxLineImportImages(File excelFile) throws Exception { + Map imageMap = new HashMap<>(); + try (InputStream inputStream = new FileInputStream(excelFile); + XSSFWorkbook workbook = new XSSFWorkbook(inputStream)) { + XSSFSheet sheet = workbook.getSheetAt(0); + XSSFDrawing drawing = sheet.getDrawingPatriarch(); + if (drawing == null) { + return imageMap; + } + for (XSSFShape shape : drawing.getShapes()) { + if (!(shape instanceof XSSFPicture)) { + continue; + } + XSSFPicture picture = (XSSFPicture) shape; + if (!(picture.getAnchor() instanceof XSSFClientAnchor)) { + continue; + } + XSSFClientAnchor anchor = (XSSFClientAnchor) picture.getAnchor(); + XSSFPictureData pictureData = picture.getPictureData(); + addLineImportImage(imageMap, anchor.getRow1(), anchor.getCol1(), anchor.getCol2(), pictureData.suggestFileExtension(), pictureData.getData()); + } + } + return imageMap; + } + + /** + * 解析xls模板中的内嵌图片,按图片左上角锚点匹配到“移动端缩略图”列。 + * + * @param excelFile xls文件 + * @return 图片映射 + * @throws Exception Excel读取失败时抛出异常 + */ + private Map extractXlsLineImportImages(File excelFile) throws Exception { + Map imageMap = new HashMap<>(); + try (InputStream inputStream = new FileInputStream(excelFile); + HSSFWorkbook workbook = new HSSFWorkbook(inputStream)) { + HSSFSheet sheet = workbook.getSheetAt(0); + HSSFPatriarch drawing = sheet.getDrawingPatriarch(); + if (drawing == null) { + return imageMap; + } + for (HSSFShape shape : drawing.getChildren()) { + if (!(shape instanceof HSSFPicture)) { + continue; + } + HSSFPicture picture = (HSSFPicture) shape; + if (!(picture.getAnchor() instanceof HSSFClientAnchor)) { + continue; + } + HSSFClientAnchor anchor = (HSSFClientAnchor) picture.getAnchor(); + HSSFPictureData pictureData = picture.getPictureData(); + addLineImportImage(imageMap, anchor.getRow1(), anchor.getCol1(), anchor.getCol2(), pictureData.suggestFileExtension(), pictureData.getData()); + } + } + return imageMap; + } + + /** + * 将匹配到缩略图列的图片加入映射,重复图片只保留同一行第一张。 + * + * @param imageMap 图片映射 + * @param rowIndex 图片左上角锚点行下标 + * @param colIndex 图片左上角锚点列下标 + * @param endColIndex 图片右下角锚点列下标 + * @param extension 图片扩展名 + * @param data 图片二进制内容 + */ + private void addLineImportImage(Map imageMap, int rowIndex, int colIndex, int endColIndex, String extension, byte[] data) { + int imageEndColIndex = Math.max(colIndex, endColIndex); + boolean coverThumbnailColumn = colIndex <= LINE_IMPORT_THUMBNAIL_COLUMN_INDEX && imageEndColIndex >= LINE_IMPORT_THUMBNAIL_COLUMN_INDEX; + if (rowIndex < LINE_IMPORT_HEADER_ROWS || !coverThumbnailColumn || data == null || data.length == 0) { + return; + } + + int dataIndex = rowIndex - LINE_IMPORT_HEADER_ROWS; + TheRapyLineImportImageMode imageMode = new TheRapyLineImportImageMode(); + imageMode.setRowIndex(dataIndex); + imageMode.setExtension(extension); + imageMode.setFileName("line-thumbnail-" + (dataIndex + 1) + "." + StrUtil.blankToDefault(extension, "png")); + imageMode.setData(data); + imageMap.putIfAbsent(dataIndex, imageMode); + } + + /** + * 构建与页面线路类型一致的Excel下拉选项。 + * + * @return 线路类型下拉选项 + */ + private String[] buildRegionalNatureExcelOptions() { + if (!TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06"})) { + return new String[]{"省内线路_省内"}; + } + return new String[]{"省内线路_省内", "省外线路_省外"}; + } + + /** + * 构建与页面组织形式一致的Excel下拉选项。 + * + * @return 组织形式下拉选项 + */ + private String[] buildSignUpModeExcelOptions() { + List options = new ArrayList<>(); + if (TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06", "H04"})) { + options.add("分工会组织_1"); + } + if (TherapyContext.hasAnyRoles(new String[]{"sysadmin", "A06"})) { + options.add("校工会组织_2"); + } + return options.toArray(new String[0]); + } + + @At + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.line") + public void exportTemplate(HttpServletResponse response) { + try { + //查旅行社,转数组 + List travelAgencys = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("serialNumber")); + List excelTravelAgencys = travelAgencys.stream().map(v -> v.getTravelAgencyName() + "_" + v.getId()).collect(Collectors.toList()); + String[] excelTravelAgencyArrs = excelTravelAgencys.toArray(new String[excelTravelAgencys.size()]); + + //查标段,转数组 + List lots = dao.query(TheRapyRecuperationLot.class, Cnd.NEW().asc("id")); + List excelLots = lots.stream().map(v -> v.getLotName() + "_" + v.getId()).collect(Collectors.toList()); + String[] excelLotArrs = excelLots.toArray(new String[excelLots.size()]); + + TherapyDownload.excelResponse(response, "线路导入模版.xls"); + Class excelModeClass = TheRapyTravelLineExcelMode.class; + Field[] excelModeClassDeclaredFields = excelModeClass.getDeclaredFields(); + + //字段过滤 + List needAddReplaceFields = Arrays.stream(excelModeClassDeclaredFields).filter(v -> List.of("travelAgencyId", "lotId", "regionalNature").contains(v.getName())).collect(Collectors.toList()); + + //循环TheRapyTravelLineExcelMode需要下拉数据的字段 + for (Field field : needAddReplaceFields) { + Excel excelAnnotation = field.getAnnotation(Excel.class); + if (Lang.isNotEmpty(excelAnnotation)) { + InvocationHandler invocationHandler = Proxy.getInvocationHandler(excelAnnotation); + Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues"); + memberValues.setAccessible(true); + Map e = (Map) memberValues.get(invocationHandler); + e.put("addressList", true); + if (field.getName().equals("travelAgencyId")) { + e.put("replace", excelTravelAgencyArrs); + } else if (field.getName().equals("lotId")) { + e.put("replace", excelLotArrs); + } else if (field.getName().equals("regionalNature")) { + e.put("replace", new String[]{"省内_省内", "省外_省外"}); + } + } + } + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook sheets = ExcelExportUtil.exportExcel(exportParams, TheRapyTravelLineExcelMode.class, new ArrayList<>()); + ServletOutputStream outputStream = response.getOutputStream(); + sheets.write(outputStream); + outputStream.close(); + } catch (Exception e) { + log.error(e.getMessage()); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java new file mode 100644 index 0000000..ef4b811 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/basicManage/TheRapyRecuperationTravelAgencyController.java @@ -0,0 +1,279 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.basicManage; + +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.PageUtil; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyTravelAgencyExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService; +import lombok.extern.slf4j.Slf4j; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.mvc.annotation.*; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + + +/** + * 疗休养旅行社管理 + * + * @author jug + * @date 2022/05/31 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/travelAgency") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationTravelAgencyController { + + @Inject + private TheRapyRecuperationTravelAgencyService travelAgencyService; + @Inject + private Dao dao; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html") + @SaCheckPermission("staffTherapyRecuperation.travelAgency") + public void index() { + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object pageData(PageForm pageForm, Integer year, String keywords) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("year", "=", year); + if (StrUtil.isNotBlank(keywords)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.orLike("contact", keywords); + seg.orLike("travelAgencyName", keywords); + seg.orLike("serialNumber", keywords); + cnd.and(seg); + } + if (StrUtil.isAllNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) { + cnd.orderBy(pageForm.getPageOrderName(), PageUtil.getOrder(pageForm.getPageOrderBy())); + } else { + cnd.asc("serialNumber * 1"); + } + return travelAgencyService.pageData(pageForm, cnd); + } + + /** + * 提交 + * + * @param travelAgency 旅行社 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object doSubmit(@Param("travelAgency") TheRapyRecuperationTravelAgency travelAgency) { + if (StrUtil.isBlank(travelAgency.getId())) { + if (travelAgencyService.count(Cnd.where("serialNumber", "=", travelAgency.getSerialNumber())) > 0) { + return Result.error("编号已存在"); + } + travelAgencyService.addTravelAgency(travelAgency); + } else { + if (travelAgencyService.count(Cnd.where("serialNumber", "=", travelAgency.getSerialNumber()).and("id", "!=", travelAgency.getId())) > 0) { + return Result.error("编号已存在"); + } + travelAgencyService.editTravelAgency(travelAgency); + } + return null; + } + + /** + * 开启或关闭旅行社 + * + * @param id 旅行社id + * @return {@link Object} + */ + @At("/openClosedTravelAgency/?") + @POST + @ViReturn + @SaCheckLogin + public Object openClosedTravelAgency(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + travelAgencyService.openTravelAgency(id); + return null; + } + + /** + * 删除旅行社 + * + * @param id 旅行社id + * @return {@link Object} + */ + @At("/deleteTravelAgency/?") + @POST + @ViReturn + @SaCheckLogin + public Object deleteTravelAgency(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + travelAgencyService.deleteTravelAgency(id); + return null; + } + + /** + * 查询旅行社 + * + * @param year 年度 + * @return {@link Object} + */ + @At("/selectTravelAgency") + @ViReturn + @SaCheckLogin + public Object selectTravelAgency(Integer year) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("year", "=", year); + return travelAgencyService.selectAllTravelAgencyByYear(cnd); + } + + + /** + * 年度区间查询旅行社 + * + * @param startYear 开始一年 + * @param endYear 结束一年 + * @return {@link Object} + */ + @At("/selectTravelAgencyByYears") + @ViReturn + @SaCheckLogin + public Object selectTravelAgencyByYears(Integer startYear, Integer endYear, Integer year) { + Cnd cnd = Cnd.NEW(); + if(startYear != null && endYear != null) { + cnd.andEX("year", ">=", startYear); + cnd.andEX("year", "<=", endYear); + }else { + cnd.andEX("year", "=", year); + } + return travelAgencyService.selectAllTravelAgencyByYear(cnd); + } + + + /** + * 根据旅行社id查线路 + * + * @param agencyId 代理id + * @return {@link Object} + */ + @At("/selectLineByAgencyId") + @ViReturn + @SaCheckLogin + public Object selectLineByAgencyId(String agencyId) { + Sql sql = Sqls.create(""" + SELECT id,lineName FROM `staff_therapy_line` WHERE travelAgencyId=@travelAgencyId + """).setParam("travelAgencyId", agencyId); + return travelAgencyService.listMap(sql); + } + + + /** + * 旅行社导入 + * + * @param file + * @return + */ + @At + @ViReturn + @SaCheckLogin + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @Aop(TransAop.READ_COMMITTED) + public Object travelAgencyImport(TempFile file) { + if (Lang.isEmpty(file)) { + return Result.error("上传的文件不能为空"); + } + String extName = FileUtil.extName(file.getFile()); + if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { + return Result.error("请上传xls,xlsx文件"); + } + List excelList; + + try { + ImportParams importParams = new ImportParams(); +// importParams.setTitleRows(1); + excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelAgencyExcelMode.class, importParams); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("读取不到数据,请检查excel文件格式"); + } + + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + try { + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getYear().toString())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTravelAgencyName()))) { + return Result.error("年度和旅行社名称不能为空"); + } + List travelAgency = ExcelImportUtil.importExcel(file.getFile(), TheRapyTravelAgencyExcelMode.class, new ImportParams()); + + List travelAgencyList = dao.query(TheRapyRecuperationTravelAgency.class, Cnd.NEW().desc("id")); + Map map = travelAgencyList.stream().collect(Collectors.toMap(v -> v.getTravelAgencyName(), v -> v.getId())); + + List list = new ArrayList<>(); + for (TheRapyTravelAgencyExcelMode travel : travelAgency) { + TheRapyRecuperationTravelAgency agency = new TheRapyRecuperationTravelAgency(); + if (Strings.isNotBlank(map.get(travel.getTravelAgencyName()))){ + agency.setId(map.get(travel.getTravelAgencyName())); + } + if (travel.getIsDisabled().equals("是")) { + agency.setDisabled(false); + } else if (travel.getIsDisabled().equals("否")) { + agency.setDisabled(true); + } + agency.setContact(travel.getContact()); + agency.setTravelAgencyName(travel.getTravelAgencyName()); + agency.setSerialNumber(travel.getSerialNumber()); + agency.setEmail(travel.getEmail()); + agency.setMaxUndertakeNumber(travel.getMaxUndertakeNumber()); + agency.setContactMobileNumber(travel.getContactMobileNumber()); + agency.setNote(travel.getNote()); + agency.setYear(travel.getYear()); + agency.setOfficialWebsite(travel.getOfficialWebsite()); + list.add(agency); + } + dao.insertOrUpdate(list); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("导入旅行社失败"); + } + + return null; + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/mobile/MobileTheRapyRecuperationEnrollController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/mobile/MobileTheRapyRecuperationEnrollController.java new file mode 100644 index 0000000..30354e6 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/mobile/MobileTheRapyRecuperationEnrollController.java @@ -0,0 +1,74 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.mobile; + +import cn.dev33.satoken.annotation.SaCheckLogin; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +/** + * @Author JyuHsin + * @Date 2022/6/2 + * @Description 疗休养页面跳转controller + */ +@IocBean +@At("/platform/staffTherapyRecuperation/mobile") +@Ok("json:full") +public class MobileTheRapyRecuperationEnrollController { + + /** + * 手机端 首页 + */ + @At("/index") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/index.html") + @SaCheckLogin + public void index() { + + } + + /** + * 手机端 线路列表页面 + */ + @At("/mobileLineListPage") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html") + @SaCheckLogin + public void mobileLinePage() { + + } + + /** + * 手机端 线路详情页面 + */ + @At("/lineInfo") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html") + @SaCheckLogin + public void lineInfo() { + + } + + /** + * 手机端 基地详情页面 + */ + @At("/baseInfo") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html") + @SaCheckLogin + public void baseInfo() { + + } + + /** + * 手机端 我的疗休养页面 + */ + @At("/myRecuperation") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html") + @SaCheckLogin + public void myRecuperation() { + + } + + @At("/userSignInfo") + @Ok("beetl:/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html") + @SaCheckLogin + public void userSignInfo() { + + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollController.java new file mode 100644 index 0000000..2c9db4b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollController.java @@ -0,0 +1,501 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.sys.models.Sys_config; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationCommonService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.web.commons.base.Globals; +import cn.dev33.satoken.annotation.SaCheckLogin; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.*; + +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; + +/** + * @FileName io.v.nutz.therapyRecuperation.controller.process.TheRapyRecuperationEnroll + * @Description: 疗休养报名报名 + * @Author zxc + * @Date 2022/5/31:16:58 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/line/enroll") +@Ok("json:full") +public class TheRapyRecuperationEnrollController { + + /** + * 单应用部署下按选择线路时段加锁,避免同一条线路最后一个名额被并发请求同时校验通过。 + */ + private static final Map LINE_SIGN_UP_LOCKS = new ConcurrentHashMap<>(); + + @Inject + private Dao dao; + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + @Inject + private TheRapyRecuperationTravelAgencyService travelAgencyService; + + @Inject + private TheRapyRecuperationCommonService commonService; + + /** + * 线路的value集合 [0,1] + */ + static List lineValues = new ArrayList<>() {{ + add(TheRapyRecuperationType.provinceInLine.getValue()); + add(TheRapyRecuperationType.provinceOutLine.getValue()); + }}; + static List travelAgencies = new ArrayList<>() {{ + add(TheRapyRecuperationType.provinceInTravelAgency.getValue()); + }}; +// static List schoolFreeValues = new ArrayList<>() {{ +// add(TheRapyRecuperationType.schoolFree.getValue()); +// }}; + + @Inject + private TheRapyRecuperationLineService lineService; + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param unionId 选择的工会id + * @param theRapyRecuperationType 线路类型 见下枚举类 + * @param lineKeyword 移动端线路名称搜索关键字 + * @param signUpStatus 报名状态筛选,0 全部、1 报名中、2 报名已结束 + * @return {@link Object} + * @see com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object pageData(PageForm pageForm, Integer year, String unionId, int theRapyRecuperationType, Integer lineUnionType, String lineKeyword, Integer signUpStatus) { + return enrollService.enrollPageData(pageForm, year, unionId, theRapyRecuperationType, lineUnionType, lineKeyword, signUpStatus); + } + + @At + @POST + @ViReturn + @SaCheckLogin + public Object getSelectLineById(String lineId, String usId, String unionId, int theRapyRecuperationType, Integer lineUnionType, Integer signUpStatus) { + return enrollService.getSelectLineById(lineId, usId, unionId, theRapyRecuperationType, lineUnionType, signUpStatus); + } + + @At + @POST + @ViReturn + @SaCheckLogin + public Object openSignUser(String usId, String travelId, String searchKeyWord) { + return enrollService.openSignUser(usId, travelId, searchKeyWord); + } + + //获取设置了公开线路的分工会 + @At + @ViReturn + @SaCheckLogin + public Object getTheRapyUnions(Integer year, int theRapyRecuperationType) { + return enrollService.getTheRapyUnions(year, theRapyRecuperationType); + } + + + /** + * 线路报名及修改 + * + * @param enrollInfo 登记信息 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object doSignUpForLine(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) { + if (StrUtil.isBlank(enrollInfo.getId())) { + if (StrUtil.isBlank(enrollInfo.getTakePartInLineId())) { + return Result.error("请选择线路"); + } + ReentrantLock lock = LINE_SIGN_UP_LOCKS.computeIfAbsent(enrollInfo.getTakePartInLineId(), key -> new ReentrantLock()); + boolean locked = false; + try { + locked = lock.tryLock(10, TimeUnit.SECONDS); + if (!locked) { + return Result.error("当前线路报名人数较多,请稍后重试"); + } + Map validResult = validLineSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + if (validResult.containsKey(false)) { + return Result.error(validResult.get(false)); + } + enrollService.doSignUpForLine(enrollInfo); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + return Result.error("当前线路报名处理中,请稍后重试"); + } finally { + if (locked) { + lock.unlock(); + } + } + return null; + } + Map validResult = validLineSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + if (validResult.containsKey(false)) { + return Result.error(validResult.get(false)); + } + enrollService.updateSignUpLine(enrollInfo); + return null; + } + + /** + * 按当前系统疗休养版本执行线路报名校验。 + * + * @param loginName 当前登录人工号 + * @param enrollInfo 报名信息,新增时必须包含takePartInLineId,编辑时包含报名记录id + * @return 校验结果,包含false时表示不可继续保存,value为前端提示文案 + */ + private Map validLineSignUpInfo(String loginName, TheRapyRecuperationEnroll enrollInfo) { + Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion")); + Map validResult = new HashMap<>(); + if ("zjxu".equals(config.getConfigValue())) { + validResult = enrollService.validSignUpInfoForZJXU(loginName, enrollInfo); + } else if ("zjiet".equals(config.getConfigValue())) { + validResult = enrollService.validSignUpInfo(loginName, enrollInfo); + } else if ("zjnu".equals(config.getConfigValue())) { + validResult = enrollService.validSignUpInfoForZJNU(loginName, enrollInfo); + } + return validResult; + } + + /** + * 报名参加旅行社 + * + * @param enrollInfo 登记信息 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object doSignUpForTravelAgency(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) { + Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion")); + Map resultMap = new HashMap<>(); + if("zjxu".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfoForZJXU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + } else if("zjiet".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + } else if("zjnu".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfoForZJNU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + } + if (resultMap.containsKey(false)) { + return Result.error(resultMap.get(false)); + } + if (StrUtil.isBlank(enrollInfo.getId())) { + enrollService.doSignUpForTravelAgency(enrollInfo); + } else { + enrollService.updateSignUpTravelAgency(enrollInfo); + } + return null; + } + + /** + * 报名参加酒店 + * + * @param enrollInfo 登记信息 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object doSignUpForBaseManagement(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) { + Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion")); + Map resultMap = new HashMap<>(); + if("zjxu".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfoForZJXU((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + } else { + resultMap = enrollService.validSignUpInfo((String) TherapyContext.getPrincipalProperty("loginname"), enrollInfo); + } + if (resultMap.containsKey(false)) { + return Result.error(resultMap.get(false)); + } + + if (StrUtil.isBlank(enrollInfo.getId())) { + enrollService.doSignUpForHotel(enrollInfo); + } else { + enrollService.updateSignUpHotel(enrollInfo); + } + return null; + } + + @At("/findSignUpInfoById/?") + @POST + @ViReturn + @SaCheckLogin + public Object findSignUpInfoById(String id) { + return enrollService.findSignUpInfoById(id); + } + + /** + * 我报名的页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param theRapyRecuperationType rapy恢复类型 + * @param auditStateId 审核状态 + * @param signUpStateId 报名状态 全部0 已报名1 已参加2 未参加3 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object mySignUpPageData(PageForm pageForm, Integer year, int theRapyRecuperationType, Integer auditStateId, int signUpStateId) { + Cnd cnd = Cnd.NEW(); + cnd.and("e.loginName", "=", TherapyContext.getPrincipalProperty("loginname")); + switch (signUpStateId) { + case 1 -> cnd.and("1", "=", 1); + case 2 -> cnd.and("e.isTakePartIn", "=", 1); + default -> { + cnd.and("e.isTakePartIn", "=", 0); + } + } + return enrollService.mySignUpPageData(pageForm, cnd, theRapyRecuperationType, year); + } + + @At + @POST + @ViReturn + @SaCheckLogin + public Object getType() { + List inList = dao.query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省内")); + List inIds = inList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()); + List inSelectList = dao.query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", inIds)); + List inSelectIds = inSelectList.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + + List outList = dao.query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省外")); + List outIds = outList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()); + List outSelectList = dao.query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", outIds)); + List outSelectIds = outSelectList.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + + //是否报省内 + int inCount = dao.count("staff_therapy_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname")) + .and("takePartInLineId", "in", inSelectIds).and("isNormal", "=", true)); + if (inCount > 0) { + return 0; + } + //是否报省外 + int outCount = dao.count("staff_therapy_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname")) + .and("takePartInLineId", "in", outSelectIds).and("isNormal", "=", true)); + if (outCount > 0) { + return 1; + } + //是否报旅行社 + int travelCount = dao.count("staff_therapy_enroll", Cnd.where("loginName", "=", TherapyContext.getPrincipalProperty("loginname")) + .and("takePartInLineId", "is", null).and("takePartInTravelAgencyId", "is not", null)); + if (travelCount > 0) { + return 2; + } + return 0; + } + + /** + * 验证是否能报名及修改 + * + * @param enrollInfo 信息 + * @return {@link Object} + */ + @At("/validSignUpInfo") + @POST + @ViReturn + @SaCheckLogin + public Object validSignUpInfo(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) { + if (StrUtil.isBlank(enrollInfo.getTakePartInBaseManagementId()) + && StrUtil.isBlank(enrollInfo.getTakePartInTravelAgencyId()) + && StrUtil.isBlank(enrollInfo.getTakePartInLineId())) { + return Result.error("线路信息不能为空"); + } + + if (StrUtil.isBlank(enrollInfo.getLoginName())){ + enrollInfo.setLoginName(TherapyContext.getPrincipalProperty("loginname").toString()); + } + + Sys_config config = dao.fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion")); + Map resultMap = new HashMap<>(); + if("zjxu".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfoForZJXU(enrollInfo.getLoginName(), enrollInfo); + } else if("zjiet".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfo(enrollInfo.getLoginName(), enrollInfo); + } else if("zjnu".equals(config.getConfigValue())) { + resultMap = enrollService.validSignUpInfoForZJNU(enrollInfo.getLoginName(), enrollInfo); + } + if (resultMap.containsKey(false)) { + return Result.error(resultMap.get(false)); + } + if (resultMap.containsKey(true) && "当前线路所指定的旅行社可报名人数剩余1人,是否继续报名".equals(resultMap.get(true))) { + return Result.success(resultMap.get(true)); + } + return Result.success(); + } + + /** + * 删除我的报名信息 + * + * @param id id + * @return {@link Object} + */ + @At("/doDeleteMyEnrollInfoById/?") + @POST + @ViReturn + @SaCheckLogin + public Object doDeleteMyEnrollInfoById(String id) { + enrollService.deleteMyEnrollInfoById(id); + return null; + } + + + /** + * 删除我的报名信息 + * + * @param id id + * @return {@link Object} + */ + @At("/doModify/?") + @POST + @ViReturn + @SaCheckLogin + public Object doModify(String id) { + enrollService.update(Chain.make("isNormal",false).add("delFlag", true),Cnd.where("id","=",id)); + return null; + } + + /** + * 能取消吗 + * + * @param id id + * @return {@link Object} + */ + @At("/canDelete/?") + @POST + @ViReturn + @SaCheckLogin + public Object canDelete(String id) { + String errorMsg = enrollService.validateCanDeleteMyEnrollInfo(id); + if (StrUtil.isNotBlank(errorMsg)) { + return Result.error(errorMsg); + } + return null; + } + + /** + * 反馈内容 + * + * @param id id + * @param evaluationForTravelAgency 对旅行社的评价(几星) + * @param evaluationForLine 对线路的评价(几星) + * @param evaluationForJourney 对旅途的评价(几星) + * @param feedbackContent 反馈内容 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object doFeedBack(String id, String evaluationForTravelAgency, String evaluationForLine, + String evaluationForJourney, String feedbackContent) { + Chain chain = Chain.make("evaluationForTravelAgency", evaluationForTravelAgency); + chain.add("evaluationForLine", evaluationForLine); + chain.add("evaluationForJourney", evaluationForJourney); + chain.add("feedbackContent", feedbackContent); + dao.update(TheRapyRecuperationEnroll.class, chain, Cnd.where("id", "=", id)); + return null; + } + + + /** + * 获取报名人数 + * + * @param lineId 线路id + * @param unionId 工会 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckLogin + public Object getSignUpUserNum(String lineId, String unionId) { + TheRapyRecuperationEnroll enroll = dao.fetch(TheRapyRecuperationEnroll.class, Cnd.where("takePartInUnionId", "=", unionId).and("takePartInLineId", "=", lineId).and("stateId", "=", TheRapyRecuperationState.PASS)); + dao.fetchLinks(enroll, "companionList"); + + Sql sql = Sqls.create(""" + select + (select count(1) from staff_therapy_enroll where isNormal=true and takePartInUnionId = @unionId AND takePartInLineId = @lineId AND stateId = @signUpSuccessCode) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where isNormal=true and takePartInUnionId = @unionId AND takePartInLineId = @lineId AND stateId = @signUpSuccessCode)) as signUpUserFamilyNum + """); + sql.setParam("signUpSuccessCode", TheRapyRecuperationState.PASS); + sql.setParam("lineId", lineId); + sql.setParam("unionId", unionId); + Object result = Daos.query(dao, sql.toString(), Sqls.callback.map()); + return result; + } + + /** + * 手机端线路介绍所有信息 + * + * @param usId 行id + * @param usUnionId 我们工会id + * @return {@link Object} + */ + @At("/selectLineAllInfo") + @GET + @ViReturn + @SaCheckLogin + public Object selectLineAllInfo(@Param("usId") String usId, + @Param("usUnionId") String usUnionId, + @Param("year") String year) { + Assert.notBlank(usId); + return enrollService.selectLineAllInfo(usId, usUnionId, year); + } + + @At + @ViReturn + @SaCheckLogin + public Object getSchoolTime() { + TherapyUser sysUser = dao.fetch(TherapyUser.class, TherapyContext.getUserId()); + if(StrUtil.isNotBlank(sysUser.getSchoolTime())) { + DateTime schoolDate = DateUtil.parse(sysUser.getSchoolTime()); + DateTime time = DateUtil.parse(DateUtil.thisYear() + "-07-01"); + int compareResult = DateUtil.compare(schoolDate, time); + return compareResult >= 0 ? sysUser.getSchoolTime() : null; + } else { + return null; + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollJoinUserImportController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollJoinUserImportController.java new file mode 100644 index 0000000..30703ae --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationEnrollJoinUserImportController.java @@ -0,0 +1,166 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollJoinUserImportService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.FieldFilter; +import org.nutz.dao.util.Daos; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.mvc.annotation.AdaptBy; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationEnrollJoinUserImport + * @Description: 导入参加人员 + * @Author zxc + * @Date 2022/6/14:09:16 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/joinUserImport") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationEnrollJoinUserImportController { + + @Inject + private Dao dao; + + @Inject + private TheRapyRecuperationEnrollJoinUserImportService joinUserImportService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html") + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + public void index() { + } + + @At + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + @ViReturn + public Object selectLineAndTravelAgencyList(Integer year, String keyword) { + return joinUserImportService.selectLineAndTravelAgencyList(year, keyword); + } + + @At + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + public Object readExcel(@Param("file") TempFile tempFile, @Param("lineId") String lineId, @Param("travelAgencyId") String travelAgencyId) { + try { + Assert.notNull(tempFile); + File file = tempFile.getFile(); + String extName = FileUtil.extName(file); + if (!List.of("XLSX", "XLS").contains(extName.toUpperCase())) { + return Result.error("请上传excel文件"); + } + + if (StrUtil.isBlank(lineId) && StrUtil.isBlank(travelAgencyId)) { + return Result.error("参数错误"); + } + + ImportParams importParams = new ImportParams(); + List list = ExcelImportUtil.importExcel(file, TheRapyRecuperationEnroll.class, importParams); + + if (Lang.isEmpty(list)) { + return Result.error("excel无数据"); + } + + List matchList = new ArrayList<>(); + + Dao ext = Daos.ext(dao, FieldFilter.create(TheRapyRecuperationEnroll.class, "id|loginName|userName|sex|unionName|signingUptime")); + + for (TheRapyRecuperationEnroll enroll : list) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("takePartInLineId", "=", lineId); + cnd.andEX("takePartInTravelAgencyId", "=", travelAgencyId); + cnd.and("loginName", "=", enroll.getLoginName()); + TheRapyRecuperationEnroll oneEnroll = ext.fetch(TheRapyRecuperationEnroll.class, cnd); + if (Lang.isNotEmpty(oneEnroll)) { + oneEnroll.setTakePartInTime(enroll.getTakePartInTime()); + matchList.add(oneEnroll); + } + } + + return Result.success(Map.of("excelRows", list, "matchList", matchList)); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + } + + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + public Object selectLineOrTravelAgency(Integer year) { + return joinUserImportService.selectLineOrTravelAgency(year); + } + + /** + * 导入用户 + * + * @param enrolls 招收 + * @return {@link Object} + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + public Object doImportTakePartInUsers(@Param("enroll") TheRapyRecuperationEnroll[] enrolls) { + for (TheRapyRecuperationEnroll enroll : enrolls) { + enroll.setTakePartIn(true); + } + dao.updateIgnoreNull(enrolls); + return null; + } + + + /** + * 下载模板 + * + * @param response 响应 + */ + @At + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.joinUser.import") + public void downloadTemplate(HttpServletResponse response) { + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + List exampleList = new ArrayList<>(); + exampleList.add(new TheRapyRecuperationEnroll().setLoginName("2000").setUserName("张三").setTakePartInTime(new Date())); + + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, TheRapyRecuperationEnroll.class, exampleList); + try { + TherapyDownload.excelResponse(response, "参加人员.xlsx"); + workbook.write(response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationExamineController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationExamineController.java new file mode 100644 index 0000000..ba2ba2f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationExamineController.java @@ -0,0 +1,18 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationExamineController + * @Description: 疗休养报名审核 + * @Author zxc + * @Date 2022/6/1:18:16 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/line/UnionSelect") +@Ok("json:full") +public class TheRapyRecuperationExamineController { +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineAdjustmentController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineAdjustmentController.java new file mode 100644 index 0000000..2dce857 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineAdjustmentController.java @@ -0,0 +1,207 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.hutool.core.lang.Assert; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineAdjustmentService; +import lombok.extern.slf4j.Slf4j; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineAdjustment + * @Description: 线路及人员调整 + * @Author zxc + * @Date 2022/6/10:10:00 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/lineAdjustment") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationLineAdjustmentController { + + @Inject + private Dao dao; + + @Inject + private TherapyMessage msgApi; + + @Inject + private TheRapyRecuperationLineAdjustmentService adjustmentService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html") + @SaCheckPermission("staffTherapyRecuperation.line.adjustment") + public void index() { + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @return {@link Object} + */ + @At + @POST + @Ok("json:full") + @ViReturn + @SaCheckRole(value = {"sysadmin", "A06", "H04", "SYSADMIN", "SCHOOL_UNION_ADMIN", "SCHOOL_UNION_WELFARE_ADMIN", "BRANCH_UNION_ADMIN", "BRANCH_UNION_CHAIRMAN"}, mode = SaMode.OR) + public Object pageData(PageForm pageForm, + Integer year, + String lineId, + String unionId, + String keywords, + String regionalNature, + String lotId) { + return adjustmentService.pageData(pageForm, year, lineId, unionId, keywords, regionalNature, lotId); + } + + + /** + * 查询分工会报名模式线路 + * + * @param year 年度 + * @return {@link Object} + */ + @At("/findUnionSignUpModeLineList") + @POST + @Ok("json:full") + @ViReturn + @SaCheckLogin + public Object findUnionSignUpModeLineList(Integer year) { + Sql sql = Sqls.create(""" + select id,lineName from staff_therapy_line + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + cnd.andEX("year", "=", year); + sql.setCondition(cnd); + return adjustmentService.listMap(sql); + } + + + /** + * 查询分工会模式报名的用户 + * + * @param lineId lineId + * @return {@link Object} + */ + @At + @POST + @Ok("json:full") + @SaCheckLogin + public Object findUnionSignUpModeUserList(@Param("lineId") String lineId, @Param("unionId") String unionId) { + try { + Assert.notBlank(lineId); + return Result.success().addData(adjustmentService.findUnionSignUpModeUserList(lineId, unionId)); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + } + + /** + * 调整用户 + * + * @param lineId 线路id + * @param loginName 登录名 + * @return {@link Object} + */ + @At + @POST + @Ok("json:full") + @SaCheckLogin + public Object adjustmentUser(String lineId, @Param("loginNames") String[] loginName) { + try { + Assert.notBlank(lineId); + Assert.notNull(loginName); + Chain chain = Chain.makeSpecial("isNormal", "isNormal ^ 1"); + Cnd cnd = Cnd.where("takePartInLineId", "=", lineId); + cnd.and("loginName", "in", loginName); + dao.update(TheRapyRecuperationEnroll.class, chain, cnd); + return Result.success(); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + } + + + @At + @POST + @Ok("json:full") + @SaCheckLogin + public Object smsAlerts(String lineId,@Param("loginNames") String[] loginName){ + try { + Sql sql = Sqls.create(""" + SELECT + rlus.id, + rlus.unionId, + rlus.lineId, + rlus.selectUserId, + DATE_FORMAT( rlus.playStartTime, '%Y-%m-%d' ) AS playStartTime, + DATE_FORMAT( rlus.playEndTime, '%Y-%m-%d' ) AS playEndTime, + rl.lineName, + rl.regionalNature, + lot.lotName + FROM + `staff_therapy_line_union_select` rlus + LEFT JOIN `staff_therapy_line` rl ON rlus.lineId = rl.id + LEFT JOIN `staff_therapy_lot` lot ON rl.lotId = lot.id + WHERE + rlus.id = @id + """).setParam("id",lineId); + NutMap map = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + String lineName = map.getString("lineName"); + String lotName = map.getString("lotName"); + String regionalNature = map.getString("regionalNature"); + String playStartTime = map.getString("playStartTime"); + String playEndTime = map.getString("playEndTime"); + List userList = dao.query(TherapyUser.class, Cnd.where("loginname", "in", loginName)); + Map usernameMap = userList.stream().collect(Collectors.toMap(TherapyUser::getLoginname, TherapyUser::getUsername)); + if (Lang.isNotEmpty(loginName)){ + Arrays.stream(loginName).forEach(v->{ + String username = usernameMap.get(v); + String content = "%s老师您好,您报名的%s【%s-%s】(%s至%s)线路未达到成团标准,现已解散,请您选择其他线路进行报名!" + .formatted(username,lineName,lotName,regionalNature,playStartTime,playEndTime); + //msgApi.sendWxMsg(content,v); + }); + } + return Result.success(); + } catch (Exception e){ + e.printStackTrace(); + return Result.error(); + } + } + + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineClusterController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineClusterController.java new file mode 100644 index 0000000..7f4a8d8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineClusterController.java @@ -0,0 +1,128 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.hutool.core.lang.Assert; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationClusterMember; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineClusterService; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.dao.Cnd; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process.TheRapyRecuperationLineClusterController + * @Description: TODO + * @Author zxc + * @Date 2022/6/17:08:52 + * @Version V1.0 + **/ +@IocBean +@At("/platform/staffTherapyRecuperation/lineCluster") +@Ok("json:full") +public class TheRapyRecuperationLineClusterController { + + @Inject + private TheRapyRecuperationLineClusterService clusterService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html") + @SaCheckPermission("staffTherapyRecuperation.lineCluster") + public void index() { + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param keywords 关键字 + * @return {@link Object} + */ + @At + @ViReturn + @POST + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.lineCluster") + public Object pageData(PageForm pageForm, Integer year, String keywords, String unionId) { + Pagination pagination = clusterService.pageData(pageForm, year, unionId, keywords); + return pagination; + } + + + /** + * 查询组团信息 + * + * @param lineId 线路id + * @param usUnionId 归属工会id + * @return {@link Object} + */ + @At + @ViReturn + @POST + @SaCheckLogin + public Object findClusterInfo(@Param("lineId") String lineId, @Param("usUnionId") String usUnionId) { + Assert.notBlank(lineId); + Assert.notBlank(usUnionId); + return clusterService.findClusterInfo(lineId, usUnionId); + } + + /** + * 设置组团成员 + * + * @param clusters 集群 + * @return {@link Object} + */ + @At + @ViReturn + @POST + @SaCheckLogin + @SLog(tag = "疗休养", msg = "设置组团人员", param = true, result = true) + public Object setClusterMembers(@Param("clusters") String clusters, @Param("lineId") String lineId) { + NutMap nutMap = Json.fromJson(NutMap.class, clusters); + List clusterList = new ArrayList<>(); + nutMap.forEach((k, v) -> { + if (!"unSelectedUsers".equals(k)) { + TheRapyRecuperationCluster t = Lang.map2Object((Map) v, TheRapyRecuperationCluster.class); + t.setLineId(lineId); + clusterList.add(t); + if (Lang.isNotEmpty(t.getMembers())) { + for (TheRapyRecuperationClusterMember member : t.getMembers()) { + member.setLineId(lineId); + } + } + } + }); + + clusterService.setClusterMembers(clusterList, lineId); + + return null; + } + + + @At("/selectClusterInfo/?") + @ViReturn + @POST + @SaCheckLogin + public Object selectClusterInfo(String lineId) { + List clusters = clusterService.query(Cnd.where("lineId", "=", lineId)); + clusterService.fetchLinks(clusters, null); + return clusters; + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineSelectionOverviewController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineSelectionOverviewController.java new file mode 100644 index 0000000..28fa0c9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineSelectionOverviewController.java @@ -0,0 +1,461 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollBed; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollChangeRecord; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollCompanion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.LineSelectionOverviewTimeSlotVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.LineSelectionOverviewVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineUnionSelectService; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * 管理员查看全部分工会已选择线路。 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/lineSelectionOverview") +@Ok("json:full") +public class TheRapyRecuperationLineSelectionOverviewController { + + @Inject + private Dao dao; + + @Inject + private TheRapyRecuperationLineUnionSelectService lineUnionSelectService; + + /** + * 管理员查看分工会已选择线路页面。 + */ + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html") + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public void index() { + } + + /** + * 查询管理员查看线路选择情况列表。 + * + * @param pageForm 分页参数,包含 pageNumber、pageSize、pageOrderName、pageOrderBy + * @param year 年度;为空时默认当前年度 + * @param keywords 线路名称或旅行社名称关键字 + * @param unionId 分工会 ID;为空时查询全部分工会 + * @param lotId 时间标段 ID;为空时查询全部时间标段 + * @param travelAgencyId 旅行社 ID;为空时查询全部旅行社 + * @param regionalNature 线路类型;传“全部”或空时查询全部类型 + * @return 分页后的已选择线路 VO,list 字段为 {@link LineSelectionOverviewVo} + */ + @At + @POST + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public Object pageData(PageForm pageForm, + @Param(value = "year", required = false) Integer year, + @Param(value = "keywords", required = false) String keywords, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "travelAgencyId", required = false) String travelAgencyId, + @Param(value = "regionalNature", required = false) String regionalNature) { + Sql listSql = buildSelectionOverviewSql(pageForm, year, keywords, unionId, lotId, travelAgencyId, regionalNature); + Pagination pagination = lineUnionSelectService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), listSql); + List rowList = pagination.getList(); + List voList = new ArrayList<>(); + for (NutMap row : rowList) { + voList.add(new LineSelectionOverviewVo() + .setLineId(row.getString("lineId")) + .setLineUnionSelectId(row.getString("lineUnionSelectId")) + .setLineUnionSelectIds(row.getString("lineUnionSelectIds")) + .setYear(row.getInt("year")) + .setSerialNumber(row.getInt("serialNumber")) + .setLineName(row.getString("lineName")) + .setRegionalNature(row.getString("regionalNature")) + .setLotName(row.getString("lotName")) + .setPlayTimes(row.getString("playTimes")) + .setSignUpTimes(row.getString("signUpTimes")) + .setAdjustSignUpEndTime(row.getString("adjustSignUpEndTime")) + .setSignUpMode(row.getInt("signUpMode")) + .setUnionId(row.getString("unionId")) + .setUnionName(row.getString("unionName")) + .setIsOpen(toBoolean(row.get("isOpen")))); + } + pagination.setList(voList); + return pagination; + } + + /** + * 导出管理员查看线路选择情况列表。 + * + * @param pageForm 排序参数,包含 pageOrderName、pageOrderBy;导出不使用分页参数 + * @param year 年度;为空时默认当前年度 + * @param keywords 线路名称或旅行社名称关键字 + * @param unionId 分工会 ID;为空时导出全部分工会 + * @param lotId 时间标段 ID;为空时导出全部时间标段 + * @param travelAgencyId 旅行社 ID;为空时导出全部旅行社 + * @param regionalNature 线路类型;传“全部”或空时导出全部类型 + * @param response HTTP 响应对象,方法直接写出 xlsx 文件,无 JSON 返回 + */ + @At + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public void doExportExcel(PageForm pageForm, + @Param(value = "year", required = false) Integer year, + @Param(value = "keywords", required = false) String keywords, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "travelAgencyId", required = false) String travelAgencyId, + @Param(value = "regionalNature", required = false) String regionalNature, + HttpServletResponse response) throws IOException { + Sql listSql = buildSelectionOverviewSql(pageForm, year, keywords, unionId, lotId, travelAgencyId, regionalNature); + List list = queryMapList(listSql); + + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("选择工会", "unionName", 25)); + exportEntities.add(new ExcelExportEntity("线路名称", "lineName", 35)); + exportEntities.add(new ExcelExportEntity("线路类型", "regionalNature", 15)); + exportEntities.add(new ExcelExportEntity("报名时间", "signUpTimes", 30)); + exportEntities.add(new ExcelExportEntity("出行时间", "playTimes", 40)); + + TherapyDownload.excelResponse(response, "线路选择情况.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list); + workbook.write(response.getOutputStream()); + workbook.close(); + } + + /** + * 查询某个分工会已选择线路的出行时间段。 + * + * @param lineId 线路 ID,对应 staff_therapy_line.id + * @param unionId 分工会 ID,对应 sys_union.id + * @param year 年度;为空时默认当前年度 + * @return 出行时间段 VO 列表,元素为 {@link LineSelectionOverviewTimeSlotVo} + */ + @At + @POST + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public Object timeSlots(@Param("lineId") String lineId, + @Param("unionId") String unionId, + @Param(value = "year", required = false) Integer year) { + Assert.notBlank(lineId, "请选择线路"); + Assert.notBlank(unionId, "请选择分工会"); + Sql sql = Sqls.create(""" + SELECT + us.id, + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.adjustSignUpEndTime, + us.playStartTime, + us.playEndTime, + us.travelAgencyId, + ta.travelAgencyName, + us.contact, + us.contactPhone, + us.principal, + us.principalContact, + us.trafficTools, + us.estimatedCost, + us.estimatedFamilyNumbers, + us.maxPeopleNumber, + us.enable + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = us.travelAgencyId + WHERE + us.lineId = @lineId + AND us.unionId = @unionId + AND us.signUpMode = 1 + AND YEAR(us.selectTime) = @year + ORDER BY + us.playStartTime ASC + """); + sql.setParam("lineId", lineId); + sql.setParam("unionId", unionId); + sql.setParam("year", year == null ? DateUtil.thisYear() : year); + List rowList = queryMapList(sql); + List voList = new ArrayList<>(); + for (NutMap row : rowList) { + voList.add(new LineSelectionOverviewTimeSlotVo() + .setId(row.getString("id")) + .setSignUpStartTime(toDate(row.get("signUpStartTime"))) + .setSignUpEndTime(toDate(row.get("signUpEndTime"))) + .setChangeEndTime(toDate(row.get("changeEndTime"))) + .setAdjustSignUpEndTime(toDate(row.get("adjustSignUpEndTime"))) + .setPlayStartTime(toDate(row.get("playStartTime"))) + .setPlayEndTime(toDate(row.get("playEndTime"))) + .setTravelAgencyId(row.getString("travelAgencyId")) + .setTravelAgencyName(row.getString("travelAgencyName")) + .setContact(row.getString("contact")) + .setContactPhone(row.getString("contactPhone")) + .setPrincipal(row.getString("principal")) + .setPrincipalContact(row.getString("principalContact")) + .setTrafficTools(row.getString("trafficTools")) + .setEstimatedCost(row.getString("estimatedCost")) + .setEstimatedFamilyNumbers(row.getInt("estimatedFamilyNumbers")) + .setMaxPeopleNumber(row.getInt("maxPeopleNumber")) + .setEnable(toBoolean(row.get("enable")))); + } + return voList; + } + + /** + * 管理员修改某个分工会已选择线路的出行时间段。 + * + * @param lineUnionSelects 出行时间段数组,包含报名时间、出行时间、旅行社、联系人、人数和启用状态等字段 + * @param lineId 线路 ID,对应 staff_therapy_line.id + * @param unionId 分工会 ID,对应 sys_union.id + * @param year 年度;为空时默认当前年度 + * @return ViReturn 统一包装结果,成功时 data 为空 + */ + @At + @POST + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + @Aop(TransAop.READ_COMMITTED) + public Object saveTimeSlots(@Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects, + @Param("lineId") String lineId, + @Param("unionId") String unionId, + @Param(value = "year", required = false) Integer year) { + Assert.notBlank(lineId, "请选择线路"); + Assert.notBlank(unionId, "请选择分工会"); + lineUnionSelectService.adminSaveLineTimes(lineUnionSelects, lineId, unionId, year); + return null; + } + + /** + * 管理员取消分工会已选择线路。 + * + * @param lineId 线路 ID,对应 staff_therapy_line.id + * @param unionId 分工会 ID,对应 sys_union.id + * @param year 年度;为空时默认当前年度 + * @return ViReturn 统一包装结果,成功时 data 为空 + */ + @At + @POST + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + @Aop(TransAop.READ_COMMITTED) + public Object cancelLine(@Param("lineId") String lineId, + @Param("unionId") String unionId, + @Param(value = "year", required = false) Integer year) { + Assert.notBlank(lineId, "请选择线路"); + Assert.notBlank(unionId, "请选择分工会"); + Integer queryYear = year == null ? DateUtil.thisYear() : year; + + List unionSelects = lineUnionSelectService.query(Cnd.where("lineId", "=", lineId) + .and("unionId", "=", unionId) + .and("signUpMode", "=", 1) + .and("YEAR(selectTime)", "=", queryYear)); + if (Lang.isEmpty(unionSelects)) { + throw Lang.makeThrow("未找到该分工会选择的线路"); + } + + // 取消线路会清理该分工会该线路下所有选择时段,以及这些时段关联的报名、床位、同伴和变更记录。 + List selectIds = unionSelects.stream() + .map(TheRapyRecuperationLineUnionSelect::getId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + List enrolls = lineUnionSelectService.dao() + .query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", selectIds)); + List enrollIds = enrolls.stream() + .map(TheRapyRecuperationEnroll::getId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + List bedIds = enrolls.stream() + .map(TheRapyRecuperationEnroll::getBedInfoId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + + if (Lang.isNotEmpty(enrollIds)) { + List companions = lineUnionSelectService.dao() + .query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIds)); + List companionBedIds = companions.stream() + .map(TheRapyRecuperationEnrollCompanion::getBedInfoId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIds)); + lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "in", enrollIds)); + if (Lang.isNotEmpty(companionBedIds)) { + lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", companionBedIds)); + } + lineUnionSelectService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIds)); + } + if (Lang.isNotEmpty(bedIds)) { + lineUnionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", bedIds)); + } + lineUnionSelectService.clear(Cnd.where("id", "in", selectIds)); + return null; + } + + /** + * 查询旅行社下拉选项。 + * + * @param year 年度;为空时默认当前年度 + * @return 旅行社实体列表,前端使用 id 和 travelAgencyName + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public Object travelAgencyOptions(@Param(value = "year", required = false) Integer year) { + // 旅行社按年度维护,管理员查看页切换年度时下拉框只展示该年度可选旅行社。 + return dao.query(TheRapyRecuperationTravelAgency.class, + Cnd.where("year", "=", year == null ? DateUtil.thisYear() : year).asc("serialNumber")); + } + + /** + * 查询时间标段下拉选项。 + * + * @return 当前基础设置中的时间标段实体列表,前端使用 id 和 lotName + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.lineSelectionOverview") + public Object lotOptions() { + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + return Optional.ofNullable(config) + .map(TheRapyRecuperationConfig::getLots) + .orElseGet(ArrayList::new); + } + + private Sql buildSelectionOverviewSql(PageForm pageForm, Integer year, String keywords, String unionId, String lotId, + String travelAgencyId, String regionalNature) { + Sql listSql = Sqls.create(""" + SELECT + line.id AS lineId, + us.id AS lineUnionSelectId, + us.id AS lineUnionSelectIds, + line.year, + line.serialNumber, + line.lineName, + line.regionalNature, + lot.lotName, + IF(us.playStartTime IS NULL OR us.playEndTime IS NULL, + NULL, + CONCAT(DATE_FORMAT(us.playStartTime, '%Y-%m-%d %H:%i'), '至', DATE_FORMAT(us.playEndTime, '%Y-%m-%d %H:%i'), IFNULL(CONCAT('(', ta.travelAgencyName, ')'), '')) + ) AS playTimes, + IF(us.signUpStartTime IS NULL OR us.signUpEndTime IS NULL, + NULL, + CONCAT(DATE_FORMAT(us.signUpStartTime, '%Y-%m-%d %H:%i'), '至', DATE_FORMAT(us.signUpEndTime, '%Y-%m-%d %H:%i')) + ) AS signUpTimes, + DATE_FORMAT(us.adjustSignUpEndTime, '%Y-%m-%d %H:%i') AS adjustSignUpEndTime, + us.signUpMode, + us.unionId, + selectUnion.unionname AS unionName, + us.isOpen + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_union selectUnion ON selectUnion.id = us.unionId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = us.travelAgencyId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("us.signUpMode", "=", 1); + cnd.and("YEAR(us.selectTime)", "=", year == null ? DateUtil.thisYear() : year); + cnd.and("line.isDisabled", "=", 0); + cnd.andEX("us.unionId", "=", unionId); + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("us.travelAgencyId", "=", travelAgencyId); + if (StrUtil.isNotBlank(regionalNature) && !"全部".equals(regionalNature)) { + cnd.and("line.regionalNature", "=", regionalNature); + } + if (StrUtil.isNotBlank(keywords)) { + cnd.and(Cnd.exps("line.lineName", "like", "%" + keywords + "%") + .or("ta.travelAgencyName", "like", "%" + keywords + "%")); + } + addPageOrder(cnd, pageForm); + listSql.setCondition(cnd); + return listSql; + } + + private void addPageOrder(Cnd cnd, PageForm pageForm) { + if (pageForm == null) { + addDefaultOrder(cnd); + return; + } + String orderName = pageForm.getPageOrderName(); + String orderBy = pageForm.getPageOrderBy(); + if (StrUtil.isNotBlank(orderName) && StrUtil.isNotBlank(orderBy)) { + String direction = "ascending".equals(orderBy) ? "asc" : "desc"; + switch (orderName) { + case "lineName" -> cnd.orderBy("line.lineName", direction); + case "regionalNature" -> cnd.orderBy("line.regionalNature", direction); + case "lotName" -> cnd.orderBy("lot.lotName", direction); + case "playTime" -> cnd.orderBy("us.playStartTime", direction); + case "signUpTimes" -> cnd.orderBy("us.signUpStartTime", direction); + case "adjustSignUpEndTime" -> cnd.orderBy("us.adjustSignUpEndTime", direction); + case "signUpMode" -> cnd.orderBy("us.signUpMode", direction); + case "unionName" -> cnd.orderBy("selectUnion.unionname", direction); + case "isOpen" -> cnd.orderBy("us.isOpen", direction); + default -> addDefaultOrder(cnd); + } + } else { + addDefaultOrder(cnd); + } + } + + private void addDefaultOrder(Cnd cnd) { + // 一条出行记录对应一条线路选择记录,默认先按年度、线路编号,再按出行开始时间排序。 + cnd.desc("line.year").asc("line.serialNumber").asc("us.playStartTime").asc("selectUnion.unionname"); + } + + private List queryMapList(Sql sql) { + return (List) Daos.query(dao, sql.toString(), Sqls.callback.maps()); + } + + private Date toDate(Object value) { + return value instanceof Date ? (Date) value : null; + } + + private Boolean toBoolean(Object value) { + if (value instanceof Boolean) { + return (Boolean) value; + } + if (value instanceof Number) { + return ((Number) value).intValue() == 1; + } + return value != null && Boolean.parseBoolean(value.toString()); + } + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineUnionSelectController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineUnionSelectController.java new file mode 100644 index 0000000..6c689ba --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationLineUnionSelectController.java @@ -0,0 +1,447 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionLineSelectLimitVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineUnionSelectService; +import lombok.extern.slf4j.Slf4j; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; + +import java.util.*; +import java.util.stream.Collectors; + + +/** + * 疗休养工会选择表 + * + * @author jug + * @date 2023/06/26 + */ +@IocBean +@At(value = {"/platform/staffTherapyRecuperation/lineFghSelect", "/platform/staffTherapyRecuperation/lineXghSelect", "/platform/staffTherapyRecuperation/lineUnionSelect"}) +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationLineUnionSelectController { + + @Inject + private TherapyContext vi; + + @Inject + private Dao dao; + + @Inject + private TheRapyRecuperationLineUnionSelectService unionSelectService; + + @At("") + @Ok("re") +// @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html") + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public String index(@Param("mode") Integer mode) { + return "beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html"; + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object pageData(PageForm pageForm, Integer year, String keywords, int selectStatus, String unionId, + String lotId, String travelAgencyId, Integer mode, String regionalNature) { + + TheRapyRecuperationConfig config = unionSelectService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + Integer queryMode = mode == null ? 1 : mode; + + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.lotId", "=", lotId); + addTravelAgencyCondition(cnd, travelAgencyId); + if (!"全部".equals(regionalNature)) { + cnd.andEX("line.regionalNature", "=", regionalNature); + } + + // 按页面入口 mode 区分已选择线路:mode=1 查当前分工会选择,mode=2 查校工会选择。 + Sql hasSelectLineSql; + if (Integer.valueOf(1).equals(queryMode)) { + SqlExpressionGroup lineScope = new SqlExpressionGroup(); + if (!"全部".equals(regionalNature)) { + lineScope.or(Cnd.exps("line.createUnionId", "=", TherapyContext.getUnionId()).and("line.regionalNature", "=", regionalNature)); + } else { + lineScope.or("line.createUnionId", "=", TherapyContext.getUnionId()); + } + lineScope.or("line.createMode", "=", 2); + cnd.and(lineScope); + hasSelectLineSql = Sqls.createf(""" + select lineId from staff_therapy_line_union_select where unionId = '%s' AND signUpMode = %s AND year(selectTime) = %s + """, TherapyContext.getUnionId(), queryMode, year == null ? DateUtil.thisYear() : year); + } else { + hasSelectLineSql = Sqls.createf(""" + select lineId from staff_therapy_line_union_select where signUpMode = %s AND year(selectTime) = %s + """, queryMode, year == null ? DateUtil.thisYear() : year); + } + + /*hasSelectLineSql = Sqls.createf(""" + select lineId from staff_therapy_line_union_select where unionId = '%s' + """, Vi.getUnionId());*/ + + switch (selectStatus) { + //查询未选择的线路 + case -1 -> { + cnd.and("line.id", "not in", hasSelectLineSql); + cnd.and("line.year", "in", year == null ? Lang.array(config.getProvinceStartYear(), config.getProvinceStartYear() + 1) : year); + } + + case 0 -> { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("us.signUpMode", "is", null); + seg.or("us.signUpMode", "=", mode); + cnd.and(seg); + } + + /*case 0 -> { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or(Cnd.exps("line.id", "not in", hasSelectLineSql).and("line.createMode", "=", TheRapyRecuperationLineCreateMode.SCHOOL.getValue())); + seg.or("line.id", "in", hasSelectLineSql); + cnd.and(seg); + }*/ + + //查询已选择的线路 + case 1 -> { + cnd.and("line.id", "in", hasSelectLineSql); + cnd.and("us.signUpMode", "=", queryMode); + cnd.and("year(us.selectTime)", "=", year == null ? DateUtil.thisYear() : year); + } + } + + cnd.and("line.isDisabled", "=", 0); + + if (StrUtil.isNotBlank(keywords)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.orLike("line.lineName", keywords); + cnd.and(seg); + } + if (StrUtil.isAllNotEmpty(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) { + cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy().replace("ending", "")); + } else { + cnd.asc("createUnionId").desc("year").asc("serialNumber"); + } + return unionSelectService.pageData(pageForm, cnd, year, queryMode); + } + + /** + * 查询当前登录人所属分工会本年度线路选择数量要求和已选择数量。 + * + * @param year 年度,页面年度筛选值;为空时按当前年度统计 + * @param mode 选择线路页面类型,1 表示分工会选择线路,2 表示校工会选择线路 + * @return 分工会线路选择数量提示 VO + */ + @At + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object getUnionLineSelectLimit(Integer year, Integer mode) { + String unionId = TherapyContext.getUnionId(); + Integer queryYear = year == null ? DateUtil.thisYear() : year; + Integer queryMode = mode == null ? 1 : mode; + + UnionLineSelectLimitVo vo = new UnionLineSelectLimitVo() + .setMinProvinceOutNumber(0) + .setMinProvinceInNumber(0) + .setSelectedProvinceOutNumber(0) + .setSelectedProvinceInNumber(0); + + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + List unionLineNumberConfigs = Optional.ofNullable(config) + .map(TheRapyRecuperationConfig::getUnionLineNumberConfigs) + .orElse(Collections.emptyList()); + for (NutMap lineNumberConfig : unionLineNumberConfigs) { + if (Objects.equals(unionId, lineNumberConfig.getString("unionId"))) { + vo.setMinProvinceOutNumber(Optional.ofNullable(lineNumberConfig.getInt("minProvinceOutNumber")).orElse(0)); + vo.setMinProvinceInNumber(Optional.ofNullable(lineNumberConfig.getInt("minProvinceInNumber")).orElse(0)); + break; + } + } + + Sql selectedSql = Sqls.create(""" + SELECT + line.regionalNature, + COUNT(us.id) AS selectedNumber + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + WHERE + us.unionId = @unionId + AND us.signUpMode = @mode + AND YEAR(us.selectTime) = @year + GROUP BY + line.regionalNature + """); + selectedSql.setParam("unionId", unionId); + selectedSql.setParam("mode", queryMode); + selectedSql.setParam("year", queryYear); + List selectedList = (List) Daos.query(dao, selectedSql.toString(), Sqls.callback.maps()); + for (NutMap selected : selectedList) { + if (Objects.equals(TheRapyRecuperationProvinceType.provinceOut.getValue(), selected.getString("regionalNature"))) { + vo.setSelectedProvinceOutNumber(Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0)); + } else if (Objects.equals(TheRapyRecuperationProvinceType.provinceIn.getValue(), selected.getString("regionalNature"))) { + vo.setSelectedProvinceInNumber(Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0)); + } + } + return vo; + } + + /** + * 分工会选择线路 + * + * @param us 分工会选择线路信息 + * @return {@link Object} + */ + @At("/selectLine") + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + @Aop(TransAop.READ_COMMITTED) + public Object selectLine(TheRapyRecuperationLineUnionSelect us) { + unionSelectService.validateLineSelectTime(us.getMode()); + unionSelectService.selectLine(us); + return null; + } + + /** + * 分工会选择线路时间 + * + * @param lineUnionSelects 分工会选择线路 + * @return {@link Object} + */ + @At("/selectLineTimes") + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + @Aop(TransAop.READ_COMMITTED) + public Object selectLineTimes(@Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) { + unionSelectService.selectLineTimes(lineUnionSelects); + return null; + } + + + @At + @POST + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object selectLineInfo(@Param("lineId") String lineId, @Param("unionId") String unionId, @Param("mode") Integer mode, @Param("year") Integer year) { + try { + Assert.notBlank(lineId); + Assert.notNull(mode); + unionId = StrUtil.emptyToNull(TherapyContext.getUnionId()); + + return Result.success(unionSelectService.selectLineInfo(lineId, unionId, mode, year)); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + } + + /** + * 查询某个分工会设置的线路时间信息 + * + * @param lineId 行id + * @param usUnionId 我们工会id + * @return {@link Object} + */ + @At + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object findUsLineInfo(String lineId, String usUnionId) { + return unionSelectService.findUsLineInfo(lineId, usUnionId); + } + + @At("/deSelect") + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + @SLog(tag = "疗休养", msg = "取消选择线路", param = true, result = true) + @Aop(TransAop.READ_COMMITTED) + public Object deSelect(@Param("lineId") String lineId, @Param("unionId") String unionId, @Param("mode") Integer mode) { + try { + unionSelectService.validateLineSelectTime(mode); + Assert.notBlank(lineId); + Assert.notBlank(unionId); +// Cnd enrollCnd = Cnd.where("takePartInUnionId", "=", unionId); +// enrollCnd.and("takePartInLineId", "=", lineId); + Cnd enrollCnd = Cnd.where("unionId", "=", unionId); + enrollCnd.and("lineId", "=", lineId); + + List unionSelects = unionSelectService.query(enrollCnd); + List list = unionSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + + List enrolls = unionSelectService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", list)); + List enrollIdList = enrolls.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList()); + List bedIdList = enrolls.stream().map(TheRapyRecuperationEnroll::getBedInfoId).collect(Collectors.toList()); + //同伴信息 + List companions = unionSelectService.dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIdList)); + List comBedIdList = companions.stream().map(TheRapyRecuperationEnrollCompanion::getBedInfoId).collect(Collectors.toList()); + + //删除报名记录 + unionSelectService.dao().clear(TheRapyRecuperationEnroll.class, Cnd.where("id", "in", enrollIdList)); + //删除床位记录 + unionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", bedIdList)); + //删除同伴信息 + unionSelectService.dao().clear(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "in", enrollIdList)); + //删除变更记录 + unionSelectService.dao().clear(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "in", enrollIdList)); + //删除同伴床位信息 + unionSelectService.dao().clear(TheRapyRecuperationEnrollBed.class, Cnd.where("id", "in", comBedIdList)); + + unionSelectService.clear(enrollCnd); + return Result.success(); + } catch (Exception e) { + return Result.error(e.getMessage()); + } +// unionSelectService.deSelect(usId); + } + + /** + * 旅行社 + * + * @return {@link Object} + */ + @At + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object getTravelAgencyOptions(Integer year) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("year", "=", year); + cnd.asc("serialNumber"); + List travelAgencies = unionSelectService.dao().query(TheRapyRecuperationTravelAgency.class, cnd); + return travelAgencies; + } + + /** + * 按旅行社筛选线路,兼容未选择线路的主表旅行社和已选择线路的出行时间段旅行社。 + * + * @param cnd 当前页面查询条件 + * @param travelAgencyId 旅行社 ID,为空时不增加过滤条件 + */ + private void addTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("us.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + + /** + * 是否公开分工会选择线路 + * + * @param id 分工会选择线路id + * @return {@link Object} + */ + @At("/isOpenUnionLine/?") + @POST + @ViReturn + @SaCheckLogin + public Object isOpenUnionLine(String id) { + if (StrUtil.isBlank(id)) { + return Result.error("参数错误"); + } + dao.update(TheRapyRecuperationLineUnionSelect.class, Chain.makeSpecial("isOpen", "isOpen ^ 1"), Cnd.where("id", "=", id)); + return null; + } + + @At("/getLineConfig/?") + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + public Object getLineConfig(String id) { + Sql sql = Sqls.create("select lotId, travelAgencyId from staff_therapy_line where id = @lineId"); + sql.setParam("lineId", id); + NutMap lineInfo = (NutMap) Daos.query(dao, sql.toString(), Sqls.callback.map()); + String lotId = lineInfo != null ? lineInfo.getString("lotId") : null; + String travelAgencyId = lineInfo != null ? lineInfo.getString("travelAgencyId") : null; + TheRapyRecuperationLot lotInfo = dao.fetch(TheRapyRecuperationLot.class, lotId); + Integer cost = Optional.ofNullable(lotInfo).map(v -> v.getActivityCost()).orElse(0); + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + Integer groupNumber = Optional.ofNullable(config).map(TheRapyRecuperationConfig::getGroupNumber).orElse(0); + Integer outsideQuota = Optional.ofNullable(config).map(TheRapyRecuperationConfig::getOutsideQuota).orElse(0); + return Result.success(Map.of("cost", cost, "groupNumber", groupNumber, "outsideQuota", outsideQuota, "travelAgencyId", travelAgencyId)); + + } + + + /** + * 一键统赋时间,针对于已选择的线路 + * + * @param lineIds 线路Id数组 + * @param lineUnionSelects 出行时段 + * @return {@link Object} + */ + @At("/setGiveLineTimes") + @POST + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + @Aop(TransAop.READ_COMMITTED) + @SLog(type = "普惠疗休养", tag = "分工会/校工会选择线路", msg = "一键统赋时间,针对于已选择的线路", param = true, result = true) + public Object setGiveLineTimes(@Param("lineIds") String[] lineIds, @Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) { + if (Lang.isNotEmpty(lineUnionSelects) && Lang.isNotEmpty(lineIds)) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = lineUnionSelects[0]; + + Chain chain = Chain.make("enable", 1); + if (lineUnionSelect.getSignUpStartTime() != null) + chain.add("signUpStartTime", lineUnionSelect.getSignUpStartTime()); + if (lineUnionSelect.getSignUpEndTime() != null) + chain.add("signUpEndTime", lineUnionSelect.getSignUpEndTime()); + if (lineUnionSelect.getChangeEndTime() != null) + chain.add("changeEndTime", lineUnionSelect.getChangeEndTime()); + if (lineUnionSelect.getPlayStartTime() != null) + chain.add("playStartTime", lineUnionSelect.getPlayStartTime()); + if (lineUnionSelect.getPlayEndTime() != null) chain.add("playEndTime", lineUnionSelect.getPlayEndTime()); + if (lineUnionSelect.getAdjustSignUpEndTime() != null) chain.add("adjustSignUpEndTime", lineUnionSelect.getAdjustSignUpEndTime()); + + dao.update(TheRapyRecuperationLineUnionSelect.class, chain, Cnd.where("id", "in", lineIds)); + } + return null; + } + + + @At + @ViReturn + @SaCheckPermission(value = {"staffTherapyRecuperation.lineFghSelect", "staffTherapyRecuperation.lineXghSelect"}, mode = SaMode.OR) + @SLog(type = "普惠疗休养", tag = "分工会/校工会选择线路", msg = "是否开放对外报名", param = true, result = true) + public Object doEditOpen(String id) { + dao.update(TheRapyRecuperationLineUnionSelect.class, Chain.makeSpecial("isOpen", "isOpen ^ 1"), Cnd.where("id", "=", id)); + return null; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationStatisticsController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationStatisticsController.java new file mode 100644 index 0000000..83bff4a --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationStatisticsController.java @@ -0,0 +1,153 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.service.BaseService; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; + +import java.util.List; +import java.util.Map; + +/** + * 查询统计 + * + * @author zhf + * @date 2022/06/15 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/query/statics") +@Ok("json:full") +public class TheRapyRecuperationStatisticsController { + + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html") + @SaCheckPermission("staffTherapyRecuperation.queryStatics") + public void index() { + } + + + @At + @ViReturn + @SaCheckLogin + public Object getLineBar(String regionalNature, Integer year) { + Sql sql = Sqls.create(""" + SELECT + line.lineName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll WHERE isNormal=true and line.id = takePartInLineId ) AS enrollNum, + ( + SELECT + COUNT( 1 ) + FROM + staff_therapy_enroll_companion com + LEFT JOIN staff_therapy_enroll enroll ON enroll.id = com.trreId + WHERE + line.id = enroll.takePartInLineId + AND com.loginName IS NULL + ) AS companionNum + FROM + `staff_therapy_line` line + where line.regionalNature=@regionalNature and line.year=@year + ORDER BY + signUpStartTime DESC + """).setParam("regionalNature", regionalNature).setParam("year", year); + + return baseService.listMap(sql); + } + + + @At + @ViReturn + @SaCheckLogin + public Object getSnSwNum(Integer year) { + + Sql sql = Sqls.create(""" + SELECT + COUNT( 1 ) AS enrollNum, + ( + SELECT + COUNT( 1 ) + FROM + staff_therapy_enroll_companion com + LEFT JOIN staff_therapy_enroll enroll ON enroll.id = com.trreId + WHERE + line.id = enroll.takePartInLineId + AND com.loginName IS NULL + ) AS companionNum + FROM + staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line line ON line.id = enroll.takePartInLineId + $condition + """); + Cnd cndSn = Cnd.NEW(); + sql.setCondition(cndSn); + cndSn.and("line.regionalNature", "=", "省内"); + cndSn.and("line.year", "=", year); + List sn = baseService.listMap(sql); + + Cnd cndSw = Cnd.NEW(); + sql.setCondition(cndSw); + cndSw.and("line.regionalNature", "=", "省内"); + cndSw.and("line.year", "=", year); + List sw = baseService.listMap(sql); + + + NutMap snMap = sn.get(0); + NutMap swMap = sw.get(0); + int snEnrollNum = Strings.isNotBlank(snMap.getString("enrollNum")) ? snMap.getInt("enrollNum") : 0; + int snCompanionNum = Strings.isNotBlank(snMap.getString("companionNum")) ? snMap.getInt("companionNum") : 0; + int swEnrollNum = Strings.isNotBlank(swMap.getString("enrollNum")) ? swMap.getInt("enrollNum") : 0; + int swCompanionNum = Strings.isNotBlank(swMap.getString("companionNum")) ? swMap.getInt("companionNum") : 0; + + return Map.of("snNum", (snCompanionNum + snEnrollNum), "swNum", (swEnrollNum + snCompanionNum)); + } + + + @At + @ViReturn + @SaCheckLogin + public Object getTravelAgencyRating(Integer year) { + Sql sql = Sqls.create(""" + SELECT + agency.travelAgencyName, + ( SELECT AVG( evaluationForTravelAgency ) FROM staff_therapy_enroll where isNormal=true and agency.id=takePartInTravelAgencyId) AS avg + FROM + `staff_therapy_travel_agency` agency + WHERE + agency.`year` = @year + """).setParam("year", year); + List list = baseService.listMap(sql); + return list; + } + + @At + @ViReturn + @SaCheckLogin + public Object getLineRating(Integer year) { + Sql sql = Sqls.create(""" + SELECT + line.lineName, + ( SELECT AVG( evaluationForLine ) FROM staff_therapy_enroll where isNormal=true and line.id=takePartInLineId) AS avg + FROM + `staff_therapy_line` line + WHERE + line.`year` = @year + """).setParam("year", year); + List list = baseService.listMap(sql); + return list; + } + + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUnionQueryController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUnionQueryController.java new file mode 100644 index 0000000..8a3e795 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUnionQueryController.java @@ -0,0 +1,1093 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.TemplateExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.web.commons.base.Globals; +import com.budwk.app.base.annotation.SLog; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; +import org.nutz.trans.Trans; + +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +@IocBean +@At("/platform/staffTherapyRecuperation/query") +@Ok("json:full") +public class TheRapyRecuperationUnionQueryController { + + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + + + @Inject + private TheRapyRecuperationTravelAgencyService travelAgencyService; + + @Inject + private TheRapyRecuperationTravelAgencyService agencyService; + + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyQuery.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyQuery") + public void index() { + } + + + @At + @ViReturn + @SaCheckLogin + public Object getXlData(PageForm pageForm, + String year, + String unionId, + String takePartInLineId, + String regionalNature, + String lotId, + String state, + String selectId, + String agencyId) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + MIN(enroll.id) as enrollId, + lineu.id, + line.lineName, + line.regionalNature, + lineu.lineId, + lineu.signUpMode, + YEAR(lineu.selectTime) as `year`, + CONCAT(DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日')) AS linePlayTime, + lineu.playStartTime as playStartTime1, + lineu.playEndTime as playEndTime2, + lxs.travelAgencyName, + lxs.contact, + lxs.contactMobileNumber, + enroll.takePartInUnionId AS usUnionId, + un.unionname, + lot.lotName, + lot.lotValue, + IFNULL(enrollStats.familyNumber, 0) AS familyNumber, + IFNULL(enrollStats.lineNum, 0) AS lineNum, + IFNULL(companionStats.signUpUserFamilyNum, 0) AS signUpUserFamilyNum + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = IFNULL(lineu.travelAgencyId, line.travelAgencyId) + LEFT JOIN staff_therapy_union un ON un.id = enroll.takePartInUnionId + LEFT JOIN ( + SELECT + e.takePartInLineId, + COUNT(1) AS lineNum, + SUM(IFNULL(e.familyNumber, 0)) AS familyNumber + FROM + staff_therapy_enroll e + WHERE + e.isNormal = TRUE + AND e.stateId = @stateId + $statsCnd + GROUP BY + e.takePartInLineId + ) enrollStats ON enrollStats.takePartInLineId = lineu.id + LEFT JOIN ( + SELECT + e.takePartInLineId, + COUNT(c.id) AS signUpUserFamilyNum + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_enroll_companion c ON c.trreId = e.id + WHERE + e.isNormal = TRUE + AND e.stateId = @stateId + $statsCnd + GROUP BY + e.takePartInLineId + ) companionStats ON companionStats.takePartInLineId = lineu.id + $condition + """).setParam("stateId", TheRapyRecuperationState.PASS); + Sql countSql = Sqls.create(""" + SELECT + COUNT(1) + FROM ( + SELECT + enroll.takePartInLineId + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_union un ON un.id = enroll.takePartInUnionId + $condition + ) lineCount + """); + + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("enroll.stateId", "=", TheRapyRecuperationState.PASS); + String statsCnd = ""; + // 年度查询改为起止时间范围,避免在 signingUptime 字段上使用 YEAR() 导致索引失效。 + if (StrUtil.isNotBlank(year)) { + int nextYear = Integer.parseInt(year) + 1; + cnd.and("enroll.signingUptime", ">=", year + "-01-01 00:00:00"); + cnd.and("enroll.signingUptime", "<", nextYear + "-01-01 00:00:00"); + statsCnd = "and e.signingUptime >= '%s-01-01 00:00:00' and e.signingUptime < '%s-01-01 00:00:00'".formatted(year, nextYear); + } + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + +// sql.setVar("unionCnd", "and (takePartInUnionId='%s' or selfUnionId='%s')".formatted(Vi.getUnionId(), Vi.getUnionId())); + statsCnd += " and (e.takePartInUnionId='%s' or e.selfUnionId='%s')".formatted(TherapyContext.getUnionId(), TherapyContext.getUnionId()); + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()).or("enroll.selfUnionId", "=", TherapyContext.getUnionId())); + //cnd.and("enroll.selfUnionId", "=", Vi.getUnionId()); + /* if (Strings.isNotBlank(unionId)) { + cnd.andEX("enroll.selfUnionId", "=", unionId); + //cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", unionId).or("enroll.selfUnionId", "=", unionId)); + } else { + sql.setVar("unionCnd", "and (enroll.takePartInUnionId='%s' or enroll.selfUnionId='%s')".formatted(Vi.getUnionId(), Vi.getUnionId())); + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", Vi.getUnionId()).or("enroll.selfUnionId", "=", Vi.getUnionId())); + }*/ + } else { + if (Strings.isNotBlank(unionId)) { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", unionId).or("enroll.selfUnionId", "=", unionId)); + //cnd.and("enroll.selfUnionId", "=", unionId); + } + } + if (Strings.isNotBlank(regionalNature)) { + sql.setVar("regionalNature", "AND line.regionalNature='%s'".formatted(regionalNature)); + } + if("2".equals(state)) { + cnd.and("enroll.takePartInTravelAgencyId", "is not", null) + .and("enroll.takePartInTravelAgencyId", "!=", ""); + } else { + cnd.and("enroll.takePartInLineId", "is not", null) + .and("enroll.takePartInLineId", "!=", ""); + } + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("lineu.lineId", "=", takePartInLineId); + cnd.andEX("lineu.id", "=", selectId); + cnd.andEX("line.regionalNature", "=", regionalNature); + addLineTravelAgencyCondition(cnd, agencyId); + cnd.groupBy("enroll.takePartInLineId"); + cnd.desc("un.unioncode"); + // 报名人数和家属人数在子查询中按线路预聚合,避免主查询每一行重复执行 COUNT 子查询。 + sql.setVar("statsCnd", statsCnd); + sql.setCondition(cnd); + countSql.setCondition(cnd); + + return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql); + } + + + @At + @ViReturn + @SaCheckLogin + public Object getRyData(PageForm pageForm, String year, String unionId, String unitId, + String takePartInLineId, String regionalNature, String state, + String state2, String agencyId, String takePartInBaseManagementId, + String lotId, String selectId) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + state.stateName, + state.stateColor, + line.regionalNature, + line.lineName, + agency.travelAgencyName, + ma.baseName, + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lineu.lineId, + lineu.playStartTime, + lineu.playEndTime, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + $lotSql + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_travel_agency agency ON agency.id = IFNULL(enroll.takePartInTravelAgencyId, IFNULL(lineu.travelAgencyId, line.travelAgencyId)) + LEFT JOIN staff_therapy_base_management ma on ma.id = enroll.takePartInBaseManagementId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + if (Strings.isNotBlank(pageForm.getSearchKeyword()) && Strings.isNotBlank(pageForm.getSearchName())) { + cnd.and(Cnd.likeEX(pageForm.getSearchName(), pageForm.getSearchKeyword())); + } + if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) { + cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy().equalsIgnoreCase("ascending") ? "ASC" : "DESC"); + } + cnd.andEX("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.andEX("enroll.isNormal", "=", true); + cnd.andEX("YEAR ( enroll.signingUptime )", "=", year); + + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); +// seg.or("agency.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + cnd.and(seg); + } + + if (TherapyContext.hasAnyRoles("sysadmin,A06")) { + if (Strings.isNotBlank(unionId) && state.equals("1")) { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", unionId).or("enroll.selfUnionId", "=", unionId)); + //cnd.and("enroll.selfUnionId", "=", unionId); + } + cnd.andEX("enroll.selfUnionId", "=", unionId); + } else { + if (StrUtil.isNotBlank(state2)) { + //等于1本工会人员看自己工会线路人员 + if (state2.equals("1")) { + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else if (state2.equals("2")) { + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd.andEX("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId()); + } else if (state2.equals("3")) { + cnd.andEX("enroll.selfUnionId", "!=", TherapyContext.getUnionId()); + cnd.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else { + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd.andEX("lineu.signUpMode", "=", 2); + } + } else { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()).or("enroll.selfUnionId", "=", TherapyContext.getUnionId())); + //cnd.and("enroll.selfUnionId", "=", Vi.getUnionId()); + } + } + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("lineu.lineId", "=", takePartInLineId); + cnd.andEX("lineu.id", "=", selectId); + addEnrollTravelAgencyCondition(cnd, agencyId); + if (state.equals("1")) { + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.and("enroll.takePartInLineId", "!=", ""); + sql.setVar("lotSql", ",(select lotName from staff_therapy_lot where id = line.lotId) as lotName"); + } else if (state.equals("2")) { + cnd.and("enroll.takePartInTravelAgencyId", "is not", null); + cnd.and("enroll.takePartInTravelAgencyId", "!=", ""); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + } else if ("3".equals(state)) { + cnd.and("enroll.takePartInBaseManagementId", "is not", null); + cnd.andEX("enroll.takePartInBaseManagementId", "=", takePartInBaseManagementId); + sql.setVar("lotSql", ",(select lotName from staff_therapy_lot where id = ma.lotId) as lotName"); + } + cnd.desc("enroll.stateId"); + sql.setCondition(cnd); + Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + List list = pagination.getList(); + list.forEach(v -> { + List companionList = baseService.dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "=", v.getString("id"))); + for (TheRapyRecuperationEnrollCompanion enrollCompanion : companionList) { + baseService.fetchLinks(enrollCompanion, "bedInfo"); + } + v.setv("companionList", companionList); + }); + return pagination; + } + + @At + @ViReturn + @SaCheckLogin + public Object getLxsData(PageForm pageForm, String year, String agencyId) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + *, + files AS fileId, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll WHERE agency.id = takePartInTravelAgencyId and isNormal=true and stateId=@stateId $unionCnd $yearCnd) agencyNum + FROM + staff_therapy_travel_agency agency + $condition + """).setParam("stateId", TheRapyRecuperationState.PASS); + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + sql.setVar("unionCnd", "AND selfUnionId = '%s' ".formatted(TherapyContext.getUnionId())); + } + if (StrUtil.isNotBlank(year)) { + sql.setVar("yearCnd", "AND YEAR(signingUptime) = '%s' ".formatted(year)); + } + cnd.andEX("agency.`year`", "=", year); + cnd.andEX("agency.id", "=", agencyId); + sql.setCondition(cnd); + Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + List list = pagination.getList(); + List agencyNum = list.stream().filter(v -> v.getInt("agencyNum") > 0).collect(Collectors.toList()); + pagination.setList(agencyNum); + return pagination; + } + + @At + @ViReturn + @SaCheckLogin + public Object getJdData(PageForm pageForm, String year, String takePartInBaseManagementId, String agencyId) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + man.* , + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll WHERE man.id = takePartInBaseManagementId and isNormal=true and stateId=@stateId $unionCnd $yearCnd) agencyNum, + ta.travelAgencyName, + ta.officialWebsite, + lot.lotName, + ta.email + FROM + `staff_therapy_base_management` man + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = man.travelAgencyId + LEFT JOIN staff_therapy_lot lot ON lot.id = man.lotId + $condition + """).setParam("stateId", TheRapyRecuperationState.PASS); + if (StrUtil.isNotBlank(year)) { + sql.setVar("yearCnd", "AND YEAR(signingUptime) = '%s' ".formatted(year)); + } + cnd.andEX("man.`year`", "=", year); + cnd.andEX("man.`id`", "=", takePartInBaseManagementId); + cnd.andEX("man.travelAgencyId", "=", agencyId); + sql.setCondition(cnd); + Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + List list = pagination.getList(); + List agencyNum = list.stream().filter(v -> v.getInt("agencyNum") > 0).collect(Collectors.toList()); + pagination.setList(agencyNum); + return pagination; + } + + + @At + @ViReturn + @SaCheckLogin + public Object getSelfUnionUser(PageForm pageForm, String year, String unitId, String unionId, String state, String state2, String agencyId) { + Cnd cnd = Cnd.NEW(); + Sql sql = Sqls.create(""" + SELECT + state.stateName, + state.stateColor, + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lineu.lineId, + lineu.playStartTime, + lineu.playEndTime, + line.lineName, + line.regionalNature, + agency.travelAgencyName, + ma.baseName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_travel_agency agency ON agency.id = IFNULL(enroll.takePartInTravelAgencyId, IFNULL(lineu.travelAgencyId, line.travelAgencyId)) + LEFT JOIN staff_therapy_base_management ma on ma.id = enroll.takePartInBaseManagementId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + if (Strings.isNotBlank(pageForm.getSearchName()) && Strings.isNotBlank(pageForm.getSearchKeyword())) { + cnd.where().andLike(pageForm.getSearchName(), pageForm.getSearchKeyword()); + } + if (StrUtil.isNotBlank(pageForm.getPageOrderName()) && StrUtil.isNotBlank(pageForm.getPageOrderBy())) { + cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy().equalsIgnoreCase("ascending") ? "ASC" : "DESC"); + } + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd.andEX("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("enroll.isNormal", "=", true); + if (!TherapyContext.hasAnyRoles("sysadmin,A06")) { + if (StrUtil.isNotBlank(unionId)) { + cnd.and("enroll.selfUnionId", "=", unionId); + } else { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()).or("enroll.selfUnionId", "=", TherapyContext.getUnionId())); + //cnd.and("enroll.selfUnionId", "=", Vi.getUnionId()); + } + } else { + if (StrUtil.isNotBlank(unionId)) { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", unionId).or("enroll.selfUnionId", "=", unionId)); + //cnd.and("enroll.selfUnionId", "=", unionId); + } + } + addEnrollTravelAgencyCondition(cnd, agencyId); + cnd.desc("enroll.stateId"); + sql.setCondition(cnd); + Pagination pagination = baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + List list = pagination.getList(); + list.forEach(v -> { + List companionList = baseService.dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "=", v.getString("id"))); + for (TheRapyRecuperationEnrollCompanion enrollCompanion : companionList) { + baseService.fetchLinks(enrollCompanion, "bedInfo"); + } + v.setv("companionList", companionList); + }); + return pagination; + } + + @At + @ViReturn + @SaCheckLogin + public Object selectAgencyUser(PageForm pageForm, String id) { + return agencyService.selectAgencyUser(pageForm, id); + } + + /** + * 线路汇总按旅行社过滤,兼容线路时间段旅行社和线路主表旅行社两种来源。 + * + * @param cnd 查询条件 + * @param travelAgencyId 旅行社 ID + */ + private void addLineTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + /** + * 报名记录按旅行社过滤,覆盖自由旅行社报名、线路报名和酒店/基地报名三种数据来源。 + * + * @param cnd 查询条件 + * @param travelAgencyId 旅行社 ID + */ + private void addEnrollTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("enroll.takePartInTravelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("ma.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + @At + @Ok("void") + @ViReturn + @SaCheckLogin + public void doExport(String state, Integer year, String searchName, String searchKeyword, String unionId, + String unitId, String agencyId, String takePartInLineId, String lotId, + HttpServletResponse response) throws IOException { + Cnd cnd = Cnd.NEW(); + if (StrUtil.isNotBlank(state)) { + if (state.equals("1")) { + cnd.andEX("YEAR(signingUptime)", "=", year); + cnd.andEX("takePartInUnionId", "=", unionId); + cnd.andEX("unitId", "=", unitId); + cnd.andEX("takePartInLineId", "=", takePartInLineId); + cnd.andEX("lotId", "=", lotId); + } else { + cnd.andEX("YEAR(signingUptime)", "=", year); + cnd.andEX("takePartInTravelAgencyId", "=", agencyId); + cnd.and("takePartInTravelAgencyId", "is not", null); + } + } + + if (Strings.isNotBlank(searchKeyword) && Strings.isNotBlank(searchName)) { + cnd.and(Cnd.likeEX(searchName, searchKeyword)); + } + cnd.and("stateId", "=", TheRapyRecuperationState.PASS); + cnd.and("isNormal", "=", true); + cnd.desc("unitName"); + List enrollList = baseService.dao().query(TheRapyRecuperationEnroll.class, cnd); + enrollList.forEach(v -> { + baseService.dao().fetchLinks(v, "companionList"); + baseService.dao().fetchLinks(v, "bedInfo"); + }); + + TheRapyRecuperationConfig config = baseService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + + List arrayList = new ArrayList<>(); + enrollList.forEach(v -> { + arrayList.add(new NutMap() {{ + addv("userName", v.getUserName()); + addv("loginName", v.getLoginName()); + addv("sex", v.getSex()); + addv("unitName", v.getUnitName()); + addv("unionName", v.getUnionName()); + addv("idCard", v.getIdCard()); + addv("mobile", v.getMobile()); + addv("familyNumber", v.getFamilyNumber()); + addv("relation", "本人"); + addv("bedType", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getBedType() : null); + addv("bedNum", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getBedNum() : null); + addv("otherSleepUser", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getOtherSleepUser() : null); + addv("bz", v.getUserName()); + }}); + v.getCompanionList().forEach(c -> { + baseService.dao().fetchLinks(c, "bedInfo"); + arrayList.add(new NutMap() {{ + addv("userName", c.getUserName()); + addv("loginName", c.getLoginName()); + addv("sex", c.getSex()); + addv("unitName", null); + addv("unionName", null); + addv("idCard", c.getIdCard()); + addv("mobile", c.getMobile()); + addv("relation", c.getRelation()); + addv("bedType", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getBedType() : null); + addv("bedNum", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getBedNum() : null); + addv("otherSleepUser", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getOtherSleepUser() : null); + addv("bz", v.getUserName()); + }}); + }); + }); + + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + exportEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("性别", "sex", 20)); + exportEntities.add(new ExcelExportEntity("单位", "unitName", 20)); + exportEntities.add(new ExcelExportEntity("工会", "unionName", 20)); + exportEntities.add(new ExcelExportEntity("身份证号", "idCard", 30)); + exportEntities.add(new ExcelExportEntity("手机号", "mobile", 10)); + if (config.getFamilyInfo() == 2) { + exportEntities.add(new ExcelExportEntity("与本人关系", "relation", 10)); + exportEntities.add(new ExcelExportEntity("床型", "bedType", 10)); + exportEntities.add(new ExcelExportEntity("床位数", "bedNum", 10)); + exportEntities.add(new ExcelExportEntity("意向拼房人", "otherSleepUser", 10)); + } else { + exportEntities.add(new ExcelExportEntity("携带家属数", "familyNumber", 10)); + + } + exportEntities.add(new ExcelExportEntity("备注", "bz", 20)); + + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + new String(("报名人员.xls").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), exportEntities, arrayList); + workbook.write(response.getOutputStream()); + workbook.close(); + + } + + @At + @ViReturn + @SaCheckLogin + public Object doRemind(String id) { + List enrollList = baseService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", id)); + if (enrollList != null) { + TheRapyRecuperationLine theRapyRecuperationLine = baseService.dao().fetch(TheRapyRecuperationLine.class, Cnd.where("id", "=", enrollList.get(0).getTakePartInLineId())); + enrollList.forEach(v -> { + TherapyUser user = baseService.dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", v.getLoginName())); +// RCSCloudAPI.sendTplSms("b2f0227de27f4bb6b81d687b4e5212f8", user.getMobile(), "@1@=" + user.getUsername() + "||@2@=" + theRapyRecuperationLine.getLineName() + "", ""); + }); + } + return null; + } + + @At + @ViReturn + @SaCheckLogin + public Object getApplyNum(String state, String state2, String unionId, Integer year, String regionalNature, String takePartInLineId, String selectId, String agencyId) { + Cnd cnd1 = Cnd.NEW(); + Sql sql1 = Sqls.create(""" + SELECT + COUNT( 1 ) + FROM + staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_base_management ma ON ma.id = enroll.takePartInBaseManagementId + $condition + """); + + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + if (Strings.isNotBlank(state)) { + if (state.equals("1")) { + cnd1.andEX("line.regionalNature", "=", regionalNature); + cnd1.and("enroll.takePartInLineId", "is not", null); + cnd1.and("enroll.takePartInLineId", "!=", ""); + if (StrUtil.isBlank(state2)) { + cnd1.and(Cnd.exps("enroll.selfUnionId", "=", TherapyContext.getUnionId()).or("enroll.takePartInUnionId", "=", TherapyContext.getUnionId())); + //cnd1.and(Cnd.exps("enroll.selfUnionId", "=", Vi.getUnionId())); + } + } else if (state.equals("2")) { + cnd1.and("enroll.takePartInTravelAgencyId", "is not", null) + .and("enroll.takePartInTravelAgencyId", "!=", "") + .and("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } else { + cnd1.and("enroll.takePartInBaseManagementId", "is not", null).and("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } + if (StrUtil.isNotBlank(state2)) { + //等于1本工会人员看自己工会线路人员 + if (state2.equals("1")) { + cnd1.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd1.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else if (state2.equals("2")) { + cnd1.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd1.andEX("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId()); + } else if (state2.equals("3")) { + cnd1.andEX("enroll.selfUnionId", "!=", TherapyContext.getUnionId()); + cnd1.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else { + cnd1.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd1.andEX("lineu.signUpMode", "=", 2); + } + } + } else { + cnd1.and(Cnd.exps("enroll.selfUnionId", "=", TherapyContext.getUnionId()).or("enroll.takePartInUnionId", "=", TherapyContext.getUnionId())); + //cnd1.and(Cnd.exps("enroll.selfUnionId", "=", Vi.getUnionId())); + } + } else { + if (Strings.isNotBlank(state)) { + if (state.equals("1")) { + if (Strings.isNotBlank(unionId)) { + cnd1.and(Cnd.exps("enroll.selfUnionId", "=", unionId).or("enroll.takePartInUnionId", "=", unionId)); + } + cnd1.andEX("line.regionalNature", "=", regionalNature); + cnd1.and("enroll.takePartInLineId", "is not", null); + cnd1.and("enroll.takePartInLineId", "!=", ""); + } else if (state.equals("2")) { + cnd1.and("enroll.takePartInTravelAgencyId", "is not", null); + cnd1.and("enroll.takePartInTravelAgencyId", "!=", ""); + cnd1.andEX("enroll.selfUnionId", "=", unionId); + } else if (state.equals("3")) { + cnd1.and("enroll.takePartInBaseManagementId", "is not", null); + } else { + cnd1.andEX("lineu.signUpMode", "=", 2); + } + } else { + if (Strings.isNotBlank(unionId)) { + cnd1.and(Cnd.exps("enroll.selfUnionId", "=", unionId).or("enroll.takePartInUnionId", "=", unionId)); + //cnd1.and(Cnd.exps("enroll.selfUnionId", "=", unionId)); + } + } + } + cnd1.andEX("lineu.lineId", "=", takePartInLineId); + cnd1.andEX("lineu.id", "=", selectId); + addEnrollTravelAgencyCondition(cnd1, agencyId); + cnd1.andEX("YEAR(enroll.signingUptime)", "= ", year); + cnd1.andEX("enroll.isNormal", "= ", true); + cnd1.andEX("enroll.stateId", "= ", TheRapyRecuperationState.PASS); + + TheRapyRecuperationConfig config = baseService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + + Sql sql2 = null; + if (config.getFamilyInfo() == 2) { + sql2 = Sqls.create(""" + SELECT + count( 1 ) + FROM + staff_therapy_enroll_companion + WHERE + trreId IN ( SELECT enroll.id FROM staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_base_management ma ON ma.id = enroll.takePartInBaseManagementId $condition ) + """); + } else { + sql2 = Sqls.create(""" + SELECT sum(familyNumber) FROM staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_base_management ma ON ma.id = enroll.takePartInBaseManagementId $condition + """); + } + Cnd cnd2 = Cnd.NEW(); + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + if (Strings.isNotBlank(state)) { + if (state.equals("1")) { + cnd2.andEX("line.regionalNature", "=", regionalNature); + cnd2.and("enroll.takePartInLineId", "is not", null); + cnd2.and("enroll.takePartInLineId", "!=", ""); + if (StrUtil.isBlank(state2)) { + cnd2.and(Cnd.exps("enroll.selfUnionId", "=", TherapyContext.getUnionId()).or("enroll.takePartInUnionId", "=", TherapyContext.getUnionId())); + //cnd2.and(Cnd.exps("enroll.selfUnionId", "=", Vi.getUnionId())); + } + } else if (state.equals("2")) { + cnd2.and("enroll.takePartInTravelAgencyId", "is not", null) + .and("enroll.takePartInTravelAgencyId", "!=", "") + .and("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } else { + cnd2.and("enroll.takePartInBaseManagementId", "is not", null).and("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } + if (StrUtil.isNotBlank(state2)) { + //等于1本工会人员看自己工会线路人员 + if (state2.equals("1")) { + cnd2.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd2.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else if (state2.equals("2")) { + cnd2.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd2.andEX("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId()); + } else if ("3".equals(state2)) { + cnd2.andEX("enroll.selfUnionId", "!=", TherapyContext.getUnionId()); + cnd2.andEX("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } else { + cnd2.and("lineu.signUpMode", "=", 2); + } + } + } else { + cnd2.and(Cnd.exps("enroll.selfUnionId", "=", TherapyContext.getUnionId()).or("enroll.takePartInUnionId", "=", TherapyContext.getUnionId())); + //cnd2.and(Cnd.exps("enroll.selfUnionId", "=", Vi.getUnionId())); + } + } else { + if (Strings.isNotBlank(state)) { + if (state.equals("1")) { + if (Strings.isNotBlank(unionId)) { + cnd2.and(Cnd.exps("enroll.selfUnionId", "=", unionId).or("enroll.takePartInUnionId", "=", unionId)); + //cnd2.and(Cnd.exps("enroll.selfUnionId", "=", unionId)); + } + cnd2.andEX("line.regionalNature", "=", regionalNature); + cnd2.and("enroll.takePartInLineId", "is not", null); + cnd2.and("enroll.takePartInLineId", "!=", ""); + } else if (state.equals("2")) { + cnd2.and("enroll.takePartInTravelAgencyId", "is not", null); + cnd2.and("enroll.takePartInTravelAgencyId", "!=", ""); + cnd2.andEX("enroll.selfUnionId", "=", unionId); + } else { + cnd2.and("enroll.takePartInBaseManagementId", "is not", null); + } + } else { + cnd2.andEX("enroll.selfUnionId", "=", unionId); + } + } + cnd2.andEX("lineu.lineId", "=", takePartInLineId); + cnd2.andEX("lineu.id", "=", selectId); + addEnrollTravelAgencyCondition(cnd2, agencyId); + cnd2.andEX("YEAR(enroll.signingUptime)", "=", year); + cnd2.andEX("enroll.isNormal", "=", true); + cnd2.andEX("enroll.stateId", "=", TheRapyRecuperationState.PASS); + + + sql1.setCondition(cnd1); + int count1 = baseService.count(sql1); + sql2.setCondition(cnd2); + int count2 = 0; + if (config.getFamilyInfo() == 2) { + count2 = baseService.count(sql2); + } else { + Sql sql = Sqls.fetchInt(sql2.toString()); + baseService.dao().execute(sql); + count2 = sql.getInt(); + } + + return Map.of("count1", count1, "count2", count2); + } + + + @Inject + private TherapyEmail emailUtil; + + + @At + @ViReturn + @SaCheckLogin + @SLog(tag = "疗休养", msg = "发邮件", param = true, result = true) + public Object doEmail(String id, Integer year) { + List enrollList = baseService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInTravelAgencyId", "=", id) + .and("YEAR(signingUptime)", "=", year) + .and("stateId", "=", TheRapyRecuperationState.PASS)); + TheRapyRecuperationTravelAgency travelAgency = baseService.dao().fetch(TheRapyRecuperationTravelAgency.class, Cnd.where("id", "=", id)); + + List sysUsers = baseService.dao().query(TherapyUser.class, Cnd.NEW()); + Map userMap = sysUsers.stream().collect(Collectors.toMap(TherapyUser::getLoginname, TherapyUser::getSchoolTime)); + + if (travelAgency != null) { + enrollList.forEach(v -> { + baseService.dao().fetchLinks(v, "companionList"); + }); + List arrayList = new ArrayList<>(); + enrollList.forEach(v -> { + String schoolTime = userMap.getOrDefault(v.getLoginName(), ""); + String sTime = TherapyRecuperationCommon.getRemarkBySchoolTime(schoolTime); + + arrayList.add(new NutMap() {{ + addv("userName", v.getUserName()); + addv("loginName", v.getLoginName()); + addv("sex", v.getSex()); + addv("unitName", v.getUnitName()); + addv("unionName", v.getUnionName()); + addv("idCard", v.getIdCard()); + addv("relation", "本人"); + addv("bz", v.getUserName()); + addv("remark", sTime); + }}); + v.getCompanionList().forEach(c -> { + arrayList.add(new NutMap() {{ + addv("userName", c.getUserName()); + addv("loginName", c.getLoginName()); + addv("sex", c.getSex()); + addv("unitName", null); + addv("unionName", null); + addv("idCard", c.getIdCard()); + addv("relation", c.getRelation()); + addv("bz", v.getUserName()); + }}); + }); + }); + + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + exportEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("性别", "sex", 20)); + exportEntities.add(new ExcelExportEntity("单位", "unitName", 40)); + exportEntities.add(new ExcelExportEntity("工会", "unionName", 40)); + exportEntities.add(new ExcelExportEntity("身份证号", "idCard", 60)); + exportEntities.add(new ExcelExportEntity("与本人关系", "relation", 60)); + exportEntities.add(new ExcelExportEntity("备注", "bz", 20)); + exportEntities.add(new ExcelExportEntity("备注2", "remark", 30)); + + File xls = new File("C:\\疗休养报名信息表.xls"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(xls); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), exportEntities, arrayList); + workbook.write(fileOutputStream); + fileOutputStream.close(); + emailUtil.send(travelAgency.getEmail(), "请核查", false, xls); + if (xls.exists()) { + xls.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + return null; + } + + @At + @ViReturn + public Object doAttend(@Param("data") String multipleSelection) { + Trans.exec(() -> { + List maps = Json.fromJsonAsList(NutMap.class, multipleSelection); + maps.forEach(v -> { + Chain chain = Chain.make("lotId", v.getString("lotId")).add("takePartInTime", v.getString("takePartInTime")).add("isTakePartIn", true); + baseService.update("staff_therapy_enroll", chain, Cnd.where("id", "=", v.getString("id"))); + }); + }); + return null; + } + + + /** + * 分工会疗休养组团时间路线申报表导出 + * + * @param response + */ + @At + @Ok("void") + @SaCheckLogin + public void exportDeclareForm(HttpServletResponse response) { + Map map = new HashMap<>(); + //本分工会的所有线路 + List takePartInList = baseService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("isNormal", "=", true).and("stateId", "=", TheRapyRecuperationState.PASS).and("takePartInUnionId", "=", TherapyContext.getUnionId())); + //本分工会的参加线路人数 + long count = takePartInList.stream().filter(v -> v.getTakePartInUnionId().equals(v.getSelfUnionId())).count(); + map.put("unionTakePartInCount", count); + //其他工会参加本公会线路的人数 + long result = takePartInList.size() - count; + map.put("otherTakePartIn", result); + //每条线路的参加人数(包含其他工会的参加人数) + Map lineTakePartInCountMap = takePartInList.stream().collect(Collectors.groupingBy(s -> s.getTakePartInLineId(), Collectors.counting())); + //本公会的每条线路参加人数(不包含其他工会的人数) + Map unionTakePartInMap = takePartInList.stream().filter(v -> v.getTakePartInUnionId().equals(v.getSelfUnionId())).collect(Collectors.groupingBy(v -> v.getTakePartInLineId(), Collectors.counting())); + //所有线路 + Sql sql = Sqls.create(""" + SELECT + rs.id, + rl.lineName, + DATE_FORMAT(rs.playStartTime,'%Y-%m-%d') as playStartTime, + lot.lotName, + ta.travelAgencyName, + rs.contact, + rs.contactPhone + FROM + `staff_therapy_line_union_select` rs + left join `staff_therapy_line` rl on rs.lineId=rl.id + LEFT JOIN `staff_therapy_travel_agency` ta ON rl.travelAgencyId = ta.id + LEFT JOIN `staff_therapy_lot` lot ON rl.lotId = lot.id + where rs.signUpMode='1' and YEAR(rs.selectTime)=@year + """); + sql.setParam("year", DateUtil.thisYear()); + List lineAllList = baseService.listMap(sql); + List nutMaps = new ArrayList<>(); + //分工会线路列表 + lineAllList.forEach(v -> { + //该线路所有的参加人数(包含了其他分工会参加的) + Long lineSum = lineTakePartInCountMap.get(v.getString("id")); + if (lineSum == null || lineSum.longValue() == 0) { +// nutMaps.add(v); + } else { + v.setv("bz", ""); + nutMaps.add(v); + } + }); + for (int i = 0; i < nutMaps.size(); i++) { + nutMaps.get(i).put("index", i + 1); + } + nutMaps.forEach(v -> { + Long lineUnionSum = unionTakePartInMap.get(v.getString("id")); + if (lineUnionSum == null || lineUnionSum.longValue() == 0) { + v.setv("takePartNum", 0); + } else { + v.setv("takePartNum", unionTakePartInMap.get(v.getString("id"))); + } + }); + map.put("maplist", nutMaps); + map.put("unionName", ((TherapyUnion) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipalProperty("union")).getUnionname()); + try { + response.setContentType("application/octet-stream"); + TherapyDownload.excelResponse(response, "教职工疗休养组团时间路线申报表.xlsx"); + TemplateExportParams params = new TemplateExportParams("templates/staffbenefit/therapyRecuperation/lxy_sbb.xlsx"); + Workbook workbook = ExcelExportUtil.exportExcel(params, map); + workbook.write(response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * 分工会疗休养出行人员导出 + * + * @param response + */ + @At + @Ok("void") + @SaCheckLogin + public void exportTravelers(Integer year, HttpServletResponse response) { + Map map = new HashMap<>(); + Sql sql = Sqls.create(""" + SELECT + re.*, + rl.lineName lxymdd, + ta.travelAgencyName, + lot.lotName + FROM + `staff_therapy_enroll` re + left join `staff_therapy_line_union_select` rs on rs.id = re.takePartInLineId + LEFT JOIN `staff_therapy_line` rl ON rs.lineId=rl.id + LEFT JOIN `staff_therapy_travel_agency` ta ON ta.id = rl.travelAgencyId + LEFT JOIN `staff_therapy_lot` lot ON rl.lotId = lot.id + WHERE + rl.lineName IS NOT NULL and rs.signUpMode='1' and re.isNormal='1' + and re.takePartInUnionId=@unionid + and YEAR(re.signingUptime)=@year + and re.stateId=@stateId + """); + String unionid = ((TherapyUnion) TherapyContext.getPrincipalProperty("union")).getId(); + sql.setParam("unionid", unionid); + sql.setParam("stateId", TheRapyRecuperationState.PASS); + sql.setParam("year", year == null ? DateUtil.thisYear() : year); + List list = baseService.listMap(sql); + for (int i = 0; i < list.size(); i++) { + list.get(i).put("index", i + 1); + } + List unionList = baseService.dao().query(TherapyUnion.class, Cnd.NEW()); + Map unionMap = unionList.stream().collect(Collectors.toMap(v -> v.getId(), v -> v.getUnionname())); + list.forEach(v -> { + if (!v.getString("selfUnionId").equals(unionid)) { + v.setv("bz", unionMap.get(v.getString("selfUnionId"))); + } + }); + map.put("unionName", ((TherapyUnion) TherapyContext.getPrincipalProperty("union")).getUnionname()); + map.put("year", DateUtil.thisYear()); + map.put("schoolName", Globals.AppName); + map.put("maplist", list); + TherapyUser user = baseService.dao().fetch(TherapyUser.class, Cnd.where("id", "=", TherapyContext.getPrincipalProperty("id"))); + map.put("filler", user.getUsername()); + map.put("mobile", user.getMobile()); + Date date = new Date(); + SimpleDateFormat dateFm = new SimpleDateFormat("yyyy年MM月dd日"); + map.put("nowTime", dateFm.format(date)); + try { + response.setContentType("application/octet-stream"); + TherapyDownload.excelResponse(response, "教职工疗休养出行人员名单.xlsx"); + TemplateExportParams params = new TemplateExportParams("templates/staffbenefit/therapyRecuperation/lxy_cxry.xlsx"); + Workbook workbook = ExcelExportUtil.exportExcel(params, map); + workbook.write(response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @At + @Ok("void") + @SaCheckLogin + public void exportSignUser(Integer year, HttpServletResponse response) { + Sql sql = Sqls.create(""" + SELECT + en.userName, + en.loginName, + en.sex, + en.mobile, + en.unitName, + en.signingUptime, + if(en.takePartInLineId is not null and en.takePartInLineId != '', line.lineName, ta.travelAgencyName) as address + FROM + `staff_therapy_enroll` en + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = en.takePartInTravelAgencyId + LEFT JOIN staff_therapy_line_union_select us ON en.takePartInLineId = us.id + LEFT JOIN staff_therapy_line line ON us.lineId = line.id + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("year(signingUptime)", "=", year == null ? DateUtil.thisYear() : year); + cnd.and("stateId", "=", TheRapyRecuperationState.PASS); + cnd.and("selfUnionId", "=", TherapyContext.getUnionId()); + cnd.and("isNormal", "=", true); + cnd.asc("signingUptime"); + sql.setCondition(cnd); + List list = baseService.listMap(sql); + + for (int i = 0; i < list.size(); i++) { + list.get(i).put("index", i + 1); + } + List entityList = new ArrayList<>(); + entityList.add(new ExcelExportEntity("序号", "index", 10)); + entityList.add(new ExcelExportEntity("姓名", "userName", 20)); + entityList.add(new ExcelExportEntity("工号", "loginName", 20)); + entityList.add(new ExcelExportEntity("性别", "sex", 20)); + entityList.add(new ExcelExportEntity("联系方式", "mobile", 20)); + entityList.add(new ExcelExportEntity("所属单位", "unitName", 20)); + entityList.add(new ExcelExportEntity("报名时间", "signingUptime", 30)); + entityList.add(new ExcelExportEntity("报名线路", "address", 100)); + + try { + TherapyDownload.excelResponse(response, year + "教职工疗休养报名人员名单.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, list); + workbook.write(response.getOutputStream()); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUserQueryController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUserQueryController.java new file mode 100644 index 0000000..cf17ab3 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/process/TheRapyRecuperationUserQueryController.java @@ -0,0 +1,1348 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.process; + + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.ExcelImportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.ImportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyRecuperationEnrollExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaMode; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.dev33.satoken.annotation.SaCheckRole; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.dao.util.cri.Static; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.AdaptBy; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.POST; +import org.nutz.mvc.annotation.Param; +import org.nutz.mvc.upload.TempFile; +import org.nutz.mvc.upload.UploadAdaptor; +import org.springframework.util.CollectionUtils; + +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; + +@IocBean +@At("/platform/staffTherapyRecuperation/user/query") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationUserQueryController { + + + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyUserQuery.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyUserQuery") + public void index() { + } + + + @At + @ViReturn + @SaCheckLogin + public Object pageData(String regionalNature, Integer state, PageForm pageForm, + Integer startYear, Integer endYear, String unionId,Integer isTakePartIn, + String unitId, String takePartInLineId, String agencyId, String lotId, + String takePartInBaseManagementId, String signUpMode) { + Cnd cnd = Cnd.NEW(); + + if (Strings.isNotBlank(pageForm.getSearchKeyword()) && Strings.isNotBlank(pageForm.getSearchName())) { + cnd.and(Cnd.likeEX(pageForm.getSearchName(), pageForm.getSearchKeyword())); + } + + Sql sql; + if (state != null && state == 2) { + sql = Sqls.create(""" + SELECT + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lxs.travelAgencyName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = enroll.takePartInTravelAgencyId + $condition + """); + if (!TherapyContext.hasAnyRoles("sysadmin, A06")) { + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } + cnd.andEX("lxs.`year`", ">=", startYear); + cnd.andEX("lxs.`year`", "<=", endYear); + cnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + cnd.andEX("enroll.isTakePartIn", "=", isTakePartIn); + } else { + sql = Sqls.create(""" + SELECT + $lotSql, + line.regionalNature, + lxs.travelAgencyName, + line.lineName, + ma.baseName, + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lineu.lineId, + lineu.playStartTime, + lineu.playEndTime, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_base_management ma on ma.id = enroll.takePartInBaseManagementId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = IFNULL(lineu.travelAgencyId, line.travelAgencyId) + $condition + """); + cnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("lineu.signUpMode", "=", signUpMode); + addLineTravelAgencyCondition(cnd, agencyId); + cnd.andEX("enroll.isTakePartIn","=",isTakePartIn); + if (state == 3) { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = ma.lotId) as lotName"); + cnd.and("enroll.takePartInBaseManagementId", "is not", null); + cnd.andEX("enroll.takePartInBaseManagementId", "=", takePartInBaseManagementId); + } else { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = line.lotId) as lotName"); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.and("enroll.takePartInLineId", "!=", ""); + } + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); +// seg.or("agency.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + cnd.and(seg); + } + if (StrUtil.isNotBlank(unionId)) { + cnd.and("enroll.selfUnionId", "=", unionId); + } + } + cnd.and("enroll.isNormal", "=", true); + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.desc("enroll.unionName"); + sql.setCondition(cnd); + return baseService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @At + @ViReturn + public Object getXlLxsUserCount(Integer isTakePartIn, String unionId, Integer startYear, Integer endYear, Integer signUpMode) { + Cnd cnd = Cnd.NEW(); + cnd.andEX("YEAR(signingUptime)", ">=", startYear); + cnd.andEX("YEAR(signingUptime)", "<=", endYear); + if (StrUtil.isNotBlank(unionId)) { + cnd.and("selfUnionId", "=", unionId); + } + cnd.and("isNormal", "=", true); + cnd.and("takePartInLineId", "is not", null); + cnd.and("takePartInLineId", "!=", ""); + cnd.and("stateId", "=", TheRapyRecuperationState.PASS); + cnd.andEX("isTakePartIn", "=", isTakePartIn); + cnd.andEX("(select signUpMode from staff_therapy_line_union_select where id = takePartInLineId)", "=", signUpMode); + int count = baseService.dao().count(TheRapyRecuperationEnroll.class, cnd); + int count1 = baseService.dao().count(TheRapyRecuperationEnroll.class, Cnd.where("takePartInTravelAgencyId", "is not", null) + .and("takePartInTravelAgencyId", "!=", "") + .andEX("selfUnionId", "=", unionId) + .andEX("YEAR(signingUptime)", ">=", startYear) + .andEX("YEAR(signingUptime)", "<=", endYear) + .andEX("stateId", "=", TheRapyRecuperationState.PASS) + .andEX("isNormal", "=", true) + .andEX("isTakePartIn", "=", isTakePartIn) + .andEX("(select signUpMode from staff_therapy_line_union_select where id = takePartInLineId)", "=", signUpMode)); + int count2 = baseService.dao().count(TheRapyRecuperationEnroll.class, Cnd.where("takePartInBaseManagementId", "is not", null) + .andEX("selfUnionId", "=", unionId) + .andEX("YEAR(signingUptime)", ">=", startYear) + .andEX("YEAR(signingUptime)", "<=", endYear) + .andEX("stateId", "=", TheRapyRecuperationState.PASS) + .andEX("isNormal", "=", true) + .andEX("isTakePartIn", "=", isTakePartIn) + .andEX("(select signUpMode from staff_therapy_line_union_select where id = takePartInLineId)", "=", signUpMode)); + return Map.of("xlCount", count, "lxsCount", count1, "jdCount", count2); + } + + + /** + * 参加人员导入 + * + * @param file + * @return + */ + @At + @ViReturn + @SaCheckLogin + @AdaptBy(type = UploadAdaptor.class, args = {"ioc:fileUpload"}) + @Aop(TransAop.READ_COMMITTED) + public Object enrollImport(TempFile file) { + if (Lang.isEmpty(file)) { + return Result.error("上传的文件不能为空"); + } + String extName = FileUtil.extName(file.getFile()); + if (!List.of("xls", "xlsx").contains(extName.toLowerCase())) { + return Result.error("请上传xls,xlsx文件"); + } + //excel数据 + List excelList; + try { + ImportParams importParams = new ImportParams(); + excelList = ExcelImportUtil.importExcel(file.getFile(), TheRapyRecuperationEnrollExcelMode.class, importParams); + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("读取不到数据,请检查excel文件格式"); + } + + if (Lang.isEmpty(excelList)) { + return Result.error("读取不到数据,请检查excel文件格式"); + } + try { + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLoginName())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getUserName()))) { + return Result.error("工号和姓名不能为空"); + } + if (excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getLotId())) || excelList.stream().anyMatch(v -> StrUtil.isBlank(v.getTakePartInTime().toString()))) { + return Result.error("标段时间和参加时间不能为空"); + } + //报名的数据 + List enrollList = baseService.dao().query(TheRapyRecuperationEnroll.class, Cnd.where("YEAR(signingUptime)", "=", DateUtil.thisYear())); + Map enrollMap = enrollList.stream().collect(Collectors.toMap(v -> v.getLoginName(), v -> v)); + //时间标段数据 + List lots = baseService.dao().query(TheRapyRecuperationLot.class, Cnd.NEW()); + //修改信息 + List updateEnrollList = new ArrayList<>(); + //错误信息返回 + List errorInfos = new ArrayList<>(); + excelList.forEach(v -> { + TheRapyRecuperationEnroll enrollInfo = enrollMap.get(v.getLoginName()); + if (enrollInfo == null) { + errorInfos.add(v.getLoginName()); + } else if (lots.stream().noneMatch(l -> l.getLotName().equals(v.getLotId()))) { +// errorInfos.add("工号" + v.getLoginName() + "的报名信息错误(时间标段有误)"); + } else { + List collect = lots.stream().filter(l -> l.getLotName().equals(v.getLotId())).collect(Collectors.toList()); + TheRapyRecuperationEnroll enroll = new TheRapyRecuperationEnroll(); + enroll.setId(enrollInfo.getId()); + enroll.setTakePartInTime(v.getTakePartInTime()); + enroll.setLotId(collect.get(0).getId()); + enroll.setTakePartIn(true); + updateEnrollList.add(enroll); + } + }); + baseService.updateIgnoreNull(updateEnrollList); + + if (!CollectionUtils.isEmpty(errorInfos)) { + String[] errorArr = errorInfos.toArray(new String[errorInfos.size()]); + + StringBuffer str = new StringBuffer(); + for (String s : errorArr) { + str.append(s + ","); + } + return Result.error(str + "的人员导入失败"); + } + } catch (Exception e) { + log.error(e.getMessage()); + return Result.error("导入参加人员失败"); + } + + return null; + } + + + @At + @ViReturn + public Object doEdit(TheRapyRecuperationEnroll enroll) { + enroll.setNormal(true); + baseService.dao().updateIgnoreNull(enroll); + return null; + } + + /** + * 查询已选择线路下拉。 + * + * @param startYear 起始年度,按选择线路时间年度过滤 + * @param endYear 结束年度,按选择线路时间年度过滤 + * @param signUpMode 组织模式,1 表示分工会组织,2 表示校工会组织 + * @param regionalNature 线路类型,省内、省外或空值 + * @param flag true 表示统计等管理页面查询;false 或空表示报名查询页面按公开范围查询 + * @param disPlayUnionSelectId 需要额外展示的线路选择记录 ID,用于回显已报名线路 + * @param travelAgencyId 旅行社 ID,同时匹配线路选择记录和线路主表上的旅行社字段 + * @return List,每项包含线路选择记录 id、线路 id、线路名称、线路类型、标段、组织模式等下拉展示字段 + */ + @At + @ViReturn + public Object getUnionSelectLine(Integer startYear, Integer endYear, Integer signUpMode, String regionalNature, + Boolean flag, String disPlayUnionSelectId, String travelAgencyId) { + Sql sql = Sqls.create(""" + SELECT + rlus.id, + rlus.unionId, + rlus.lineId, + rlus.selectUserId, + DATE_FORMAT( rlus.playStartTime, '%Y-%m-%d' ) AS playStartTime, + DATE_FORMAT( rlus.playEndTime, '%Y-%m-%d' ) AS playEndTime, + rl.lineName, + rl.regionalNature, + if(rlus.signUpMode=2,'校工会','分工会') AS signUpMode, + lot.lotName, + un.unionname + FROM + `staff_therapy_line_union_select` rlus + LEFT JOIN `staff_therapy_line` rl ON rlus.lineId = rl.id + LEFT JOIN `staff_therapy_lot` lot ON rl.lotId = lot.id + LEFT JOIN staff_therapy_union un ON un.id = rlus.unionId + $condition + """); + Cnd cnd = Cnd.NEW(); + Integer queryStartYear = startYear != null ? startYear : DateUtil.thisYear(); + Integer queryEndYear = endYear != null ? endYear : queryStartYear; + if (flag == null || !flag) { + SqlExpressionGroup group = new SqlExpressionGroup(); + if (TherapyContext.hasAnyRoles("sysadmin,A06")) { + group.and("rlus.isOpen", "=", 1); + //cnd.and(Cnd.exps("rlus.isOpen", "=", 1)); + } else { + group.or("rlus.isOpen", "=", 1).or("rlus.unionId", "=", TherapyContext.getUnionId()); + //cnd.and(Cnd.exps("rlus.isOpen", "=", 1).or(); + } + if(StrUtil.isNotBlank(disPlayUnionSelectId)) { + group.or("rlus.id", "=", disPlayUnionSelectId); + } + cnd.and(group); + } else { + if (!TherapyContext.hasAnyRoles("sysadmin,A06")) { + cnd.and(Cnd.exps("rlus.selectUserId", "=", TherapyContext.getUserId()).or("rlus.unionId", "=", TherapyContext.getUnionId())); + } + cnd.andEX("rl.regionalNature", "=", regionalNature); + cnd.groupBy("rlus.lineId"); + } + cnd.and("YEAR(rlus.selectTime)", ">=", queryStartYear); + cnd.and("YEAR(rlus.selectTime)", "<=", queryEndYear); + cnd.andEX("rlus.signUpMode", "=", signUpMode); + addUnionSelectLineTravelAgencyCondition(cnd, travelAgencyId); + cnd.desc("lot.lotValue"); + cnd.desc("rl.lineName"); + sql.setCondition(cnd); + return baseService.listMap(sql); + } + + /** + * 已选择线路下拉按旅行社过滤。 + * 当前下拉 SQL 使用 rlus 和 rl 别名,因此需要匹配线路选择记录旅行社及线路主表旅行社两处字段。 + * + * @param cnd 当前线路下拉查询条件 + * @param travelAgencyId 旅行社 ID,为空时不增加过滤条件 + */ + private void addUnionSelectLineTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("rlus.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("rl.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + /** + * 查询代选路线候选人员。 + * + * @param keyword 姓名或工号关键字,前端远程搜索报名人员时传入 + * @return List 候选人员集合,包含 loginname、username、label 等下拉展示字段 + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyUserQuery") + public Object searchProxySignUpUsers(String keyword) { + return enrollService.searchProxySignUpUsers(keyword); + } + + /** + * 查询可代选的校工会和分工会线路。 + * + * @param year 主页面选择的年度,前端用于限定代选线路所属年份 + * @return List 线路选择集合,value 使用线路选择表 id,展示字段包含线路名、类型、标段和出行时间 + */ + @At + @ViReturn + @SaCheckLogin + @SaCheckPermission("staffTherapyRecuperation.TheRapyUserQuery") + public Object getProxySignUpLines(Integer year) { + return enrollService.getProxySignUpLines(year); + } + + /** + * 提交代选路线报名。 + * + * @param enrollInfo 前端 JSON 提交的代报名信息,必须包含被报名人工号 loginName 和线路选择表 id takePartInLineId; + * 家属数量模式传 familyNumber,详细家属模式传 companionList + * @return Result 校验失败时返回错误信息,成功时由 ViReturn 包装为成功响应 + */ + @At + @POST + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + @SaCheckPermission("staffTherapyRecuperation.TheRapyUserQuery") + public Object doProxySignUpForLine(@Param("enroll") TheRapyRecuperationEnroll enrollInfo) { + if (enrollInfo == null) { + return Result.error("请填写代报名信息"); + } + Map validResult = enrollService.validProxySignUpInfoForLine(enrollInfo.getLoginName(), enrollInfo); + if (validResult.containsKey(false)) { + return Result.error(validResult.get(false)); + } + enrollService.doProxySignUpForLine(enrollInfo); + return null; + } + + /** + * 线路人员查询按旅行社过滤。 + * 线路选择记录可单独维护旅行社,历史数据也可能只维护在线路主表, + * 因此同时匹配 lineu.travelAgencyId 和 line.travelAgencyId,避免漏掉任一来源的数据。 + * + * @param cnd 当前线路人员查询条件 + * @param travelAgencyId 旅行社 ID,为空时不增加过滤条件 + */ + private void addLineTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + /** + * 导出人员查询页面当前筛选结果,表头和字段含义与页面列表保持一致。 + * + * @param regionalNature 线路类型,传“省内”“省外”或空值,空值表示不过滤线路类型 + * @param state 查询分类,1 表示线路,2 表示旅行社,3 表示酒店/基地 + * @param searchName 查询字段,目前页面传 userName 或 loginName + * @param searchKeyword 查询关键字,按 searchName 对应字段进行模糊匹配 + * @param startYear 起始年度,按报名时间年度过滤 + * @param endYear 结束年度,按报名时间年度过滤 + * @param unionId 所属工会 ID,空值表示不过滤工会 + * @param unitId 所属单位 ID,空值表示不过滤单位 + * @param takePartInLineId 线路选择记录 ID,空值表示不过滤线路 + * @param agencyId 旅行社 ID,空值表示不过滤旅行社 + * @param lotId 标段 ID,空值表示不过滤标段 + * @param takePartInBaseManagementId 酒店/基地 ID,空值表示不过滤酒店/基地 + * @param signUpMode 组织模式,1 表示分工会组织,2 表示校工会组织,空值表示不过滤 + * @param isTakePartIn 是否参加,1 表示已参加,0 表示未参加,空值表示全部 + * @param response HTTP 响应对象,方法直接写出 xlsx 文件,无 JSON 返回 + */ + @At + @Ok("void") + @ViReturn + @SaCheckLogin + public void doExportViewExcel(@Param(value = "regionalNature", required = false) String regionalNature, + @Param(value = "state", required = false) Integer state, + @Param(value = "searchName", required = false) String searchName, + @Param(value = "searchKeyword", required = false) String searchKeyword, + @Param(value = "startYear", required = false) Integer startYear, + @Param(value = "endYear", required = false) Integer endYear, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "unitId", required = false) String unitId, + @Param(value = "takePartInLineId", required = false) String takePartInLineId, + @Param(value = "agencyId", required = false) String agencyId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "takePartInBaseManagementId", required = false) String takePartInBaseManagementId, + @Param(value = "signUpMode", required = false) String signUpMode, + @Param(value = "isTakePartIn", required = false) Integer isTakePartIn, + HttpServletResponse response) throws IOException { + Cnd cnd = Cnd.NEW(); + + if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) { + cnd.and(Cnd.likeEX(searchName, searchKeyword)); + } + + Sql sql; + if (state != null && state == 2) { + sql = Sqls.create(""" + SELECT + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lxs.travelAgencyName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = enroll.takePartInTravelAgencyId + $condition + """); + if (!TherapyContext.hasAnyRoles("sysadmin, A06")) { + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + } + cnd.andEX("lxs.`year`", ">=", startYear); + cnd.andEX("lxs.`year`", "<=", endYear); + cnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + cnd.andEX("enroll.isTakePartIn", "=", isTakePartIn); + } else { + sql = Sqls.create(""" + SELECT + $lotSql, + line.regionalNature, + lxs.travelAgencyName, + line.lineName, + ma.baseName, + enroll.*, + IF(enroll.isReimbursement = 1,'已报销','未报销') AS reimbursementStatus, + lineu.lineId, + lineu.playStartTime, + lineu.playEndTime, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_base_management ma on ma.id = enroll.takePartInBaseManagementId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = IFNULL(lineu.travelAgencyId, line.travelAgencyId) + $condition + """); + cnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("lineu.signUpMode", "=", signUpMode); + addLineTravelAgencyCondition(cnd, agencyId); + cnd.andEX("enroll.isTakePartIn", "=", isTakePartIn); + if (state != null && state == 3) { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = ma.lotId) as lotName"); + cnd.and("enroll.takePartInBaseManagementId", "is not", null); + cnd.andEX("enroll.takePartInBaseManagementId", "=", takePartInBaseManagementId); + } else { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = line.lotId) as lotName"); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.and("enroll.takePartInLineId", "!=", ""); + } + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + cnd.and(seg); + } + if (StrUtil.isNotBlank(unionId)) { + cnd.and("enroll.selfUnionId", "=", unionId); + } + } + cnd.and("enroll.isNormal", "=", true); + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.desc("enroll.unionName"); + sql.setCondition(cnd); + + List list = baseService.listMap(sql); + TheRapyRecuperationConfig config = baseService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + list.forEach(this::formatViewExportRow); + list = expandExportCompanionRows(list, config); + + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("一卡通号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 15)); + exportEntities.add(new ExcelExportEntity("单位", "unitName", 25)); + exportEntities.add(new ExcelExportEntity("工会", "unionName", 20)); + if (isCompanionDetailEnabled(config)) { + exportEntities.add(new ExcelExportEntity("与本人关系", "relation", 15)); + } + if (state != null && state == 2) { + exportEntities.add(new ExcelExportEntity("旅行社", "travelAgencyName", 25)); + } else { + exportEntities.add(new ExcelExportEntity("线路/酒店", "viewLineName", 30)); + exportEntities.add(new ExcelExportEntity("出行时间", "playStartTime", 20)); + exportEntities.add(new ExcelExportEntity("线路类型", "regionalNature", 15)); + exportEntities.add(new ExcelExportEntity("标段", "viewLotName", 15)); + } + exportEntities.add(new ExcelExportEntity("是否携带家属", "viewFamily", 18)); + ExcelExportEntity signingUptimeEntity = new ExcelExportEntity("报名时间", "signingUptime", 20); + signingUptimeEntity.setFormat("yyyy-MM-dd HH:mm:ss"); + exportEntities.add(signingUptimeEntity); + exportEntities.add(new ExcelExportEntity("是否参加", "viewTakePartIn", 15)); + exportEntities.add(new ExcelExportEntity("是否报销", "reimbursementStatus", 15)); + exportEntities.add(new ExcelExportEntity("参加时间", "takePartInTime", 20)); + + TherapyDownload.excelResponse(response, "人员列表.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list); + workbook.write(response.getOutputStream()); + workbook.close(); + } + + /** + * 将列表中的模板展示逻辑转换为 Excel 文本,保证导出内容与页面看到的值一致。 + * + * @param row 当前报名记录行,方法会补充 viewLineName、viewLotName、viewFamily、viewTakePartIn 等导出字段 + */ + private void formatViewExportRow(NutMap row) { + row.put("viewLineName", StrUtil.isNotBlank(row.getString("baseName")) ? row.getString("baseName") : row.getString("lineName")); + row.put("viewLotName", StrUtil.isNotBlank(row.getString("lotName")) ? row.getString("lotName") : "暂无"); + + Integer familyNumber = row.getInt("familyNumber"); + Integer isFamily = row.getInt("isFamily"); + Integer familyCount = familyNumber != null ? familyNumber : isFamily; + row.put("viewFamily", familyCount != null && familyCount > 0 ? "携带(" + familyCount + ")" : "未携带(0)"); + Object isTakePartIn = row.get("isTakePartIn"); + row.put("viewTakePartIn", Boolean.TRUE.equals(isTakePartIn) || "1".equals(String.valueOf(isTakePartIn)) ? "已参加" : "未参加"); + } + + /** + * 家属明细模式下,将报名本人行展开为“本人 + 家属”多行导出。 + * + * @param enrollRows 报名主表查询结果,每行必须包含报名记录 id 以及本人、线路、旅行社等上下文字段 + * @param config 疗休养基础配置,familyInfo 为 2 时表示家属按明细导出 + * @return 展开后的导出数据;非家属明细模式直接返回原列表 + */ + private List expandExportCompanionRows(List enrollRows, TheRapyRecuperationConfig config) { + if (CollectionUtils.isEmpty(enrollRows) || !isCompanionDetailEnabled(config)) { + return enrollRows; + } + List enrollIds = enrollRows.stream() + .map(row -> row.getString("id")) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + if (CollectionUtils.isEmpty(enrollIds)) { + return enrollRows; + } + + Sql companionSql = Sqls.create(""" + SELECT + companion.trreId, + companion.loginName, + companion.userName, + companion.sex, + companion.relation, + companion.idCard, + companion.mobile, + bed.bedType, + bed.bedNum, + bed.otherSleepUser + FROM + staff_therapy_enroll_companion companion + LEFT JOIN staff_therapy_enroll_bed bed ON bed.id = companion.bedInfoId + $condition + """); + Cnd companionCnd = Cnd.where("companion.trreId", "in", enrollIds); + companionCnd.asc("companion.trreId"); + companionSql.setCondition(companionCnd); + List companionList = baseService.listMap(companionSql); + Map> companionMap = companionList.stream() + .collect(Collectors.groupingBy(row -> row.getString("trreId"))); + + List resultList = new ArrayList<>(); + for (NutMap enrollRow : enrollRows) { + enrollRow.put("relation", "本人"); + resultList.add(enrollRow); + List companions = companionMap.get(enrollRow.getString("id")); + if (CollectionUtils.isEmpty(companions)) { + continue; + } + for (NutMap companion : companions) { + NutMap companionRow = new NutMap(); + companionRow.putAll(enrollRow); + companionRow.put("loginName", companion.getString("loginName")); + companionRow.put("userName", companion.getString("userName")); + companionRow.put("sex", companion.getString("sex")); + companionRow.put("relation", companion.getString("relation")); + companionRow.put("idCard", companion.getString("idCard")); + companionRow.put("mobile", companion.getString("mobile")); + companionRow.put("bedType", companion.getString("bedType")); + companionRow.put("bedNum", companion.get("bedNum")); + companionRow.put("otherSleepUser", companion.getString("otherSleepUser")); + companionRow.put("familyCount", null); + companionRow.put("familyNumber", null); + companionRow.put("viewFamily", "家属"); + resultList.add(companionRow); + } + } + return resultList; + } + + private boolean isCompanionDetailEnabled(TheRapyRecuperationConfig config) { + return config != null && Integer.valueOf(2).equals(config.getFamilyInfo()); + } + + @At + @Ok("void") + @ViReturn + @SaCheckLogin + public void doExportExcel(@Param(value = "regionalNature", required = false) String regionalNature, + @Param(value = "state", required = false) Integer state, + @Param(value = "searchName", required = false) String searchName, + @Param(value = "searchKeyword", required = false) String searchKeyword, + @Param(value = "startYear", required = false) Integer startYear, + @Param(value = "endYear", required = false) Integer endYear, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "unitId", required = false) String unitId, + @Param(value = "takePartInLineId", required = false) String takePartInLineId, + @Param(value = "agencyId", required = false) String agencyId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "takePartInBaseManagementId", required = false) String takePartInBaseManagementId, + @Param(value = "signUpMode", required = false) String signUpMode, + @Param(value = "types", required = false) String[] types, + @Param(value = "satisfyPeople", required = false) Boolean satisfyPeople, + HttpServletResponse response) throws IOException { + + Cnd commonCnd = Cnd.NEW(); + if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) { + // 导出查询的 searchName 由前端传 userName 或 loginName,统一限定到报名表 enroll,避免关联 user 表后字段歧义。 + String searchColumn = getEnrollSearchColumn(searchName); + if (Strings.isNotBlank(searchColumn)) { + commonCnd.and(Cnd.likeEX(searchColumn, searchKeyword)); + } + } + if (!TherapyContext.hasAnyRoles("sysadmin, A06")) { + commonCnd.and(Cnd.exps("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()).or("enroll.selfUnionId", "=", TherapyContext.getUnionId())); + } + commonCnd.and("enroll.isNormal", "=", true); + commonCnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + + //线路的查询 + Sql lineSql = Sqls.create(""" + SELECT + line.regionalNature, + lxs.travelAgencyName, + line.lineName, + lineu.signUpMode, + un.unionname AS selectUnionName, + enroll.*, + date_format( enroll.signingUptime, '%Y-%m-%d %H:%i:%s' ) signingUptimeFormat, + date_format( lineu.playStartTime, '%Y-%m-%d' ) playStartTime, + lineu.lineId, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id) familyCount, + u.schoolTime + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_user` u on enroll.loginName = u.loginname + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_union un ON un.id = lineu.unionId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = IFNULL(lineu.travelAgencyId, line.travelAgencyId) + $condition + """); + Cnd lineCnd = commonCnd.clone(); + lineCnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + lineCnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + lineCnd.andEX("enroll.selfUnitId", "=", unitId); + lineCnd.andEX("line.id", "=", takePartInLineId); + lineCnd.andEX("line.regionalNature", "=", regionalNature); + lineCnd.andEX("lineu.signUpMode", "=", signUpMode); + addLineTravelAgencyCondition(lineCnd, agencyId); + lineCnd.andEX("enroll.selfUnionId", "=", unionId); + lineCnd.and("enroll.takePartInLineId", "is not", null); + lineCnd.and("enroll.takePartInLineId", "!=", ""); + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + lineCnd.and(seg); + } + lineCnd.asc("lineName").asc("playStartTime").asc("unionName"); + lineSql.setCondition(lineCnd); + List lineEnroll = baseService.listMap(lineSql); + lineEnroll.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + + //自由组团的查询 + Sql travelSql = Sqls.create(""" + SELECT + enroll.*, + lxs.travelAgencyName, + u.schoolTime + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_user` u on enroll.loginName = u.loginname + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = enroll.takePartInTravelAgencyId + $condition + """); + Cnd travelCnd = commonCnd.clone(); + travelCnd.andEX("enroll.selfUnionId", "=", unionId); + travelCnd.andEX("lxs.`year`", ">=", startYear); + travelCnd.andEX("lxs.`year`", "<=", endYear); + travelCnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + travelCnd.and("enroll.takePartInTravelAgencyId", "is not", null); + travelCnd.and("enroll.takePartInTravelAgencyId", "!=", ""); + travelCnd.asc("travelAgencyName").desc("enroll.unionName"); + travelSql.setCondition(travelCnd); + List travelEnroll = baseService.listMap(travelSql); + travelEnroll.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + + //公共的导出表头 + ArrayList commonEntities = new ArrayList<>(); + commonEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + commonEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + commonEntities.add(new ExcelExportEntity("性别", "sex", 10)); + commonEntities.add(new ExcelExportEntity("所属单位", "unitName", 20)); + commonEntities.add(new ExcelExportEntity("所属工会", "unionName", 20)); + commonEntities.add(new ExcelExportEntity("身份证号", "idCard", 30)); + commonEntities.add(new ExcelExportEntity("手机号", "mobile", 15)); + ExcelExportEntity entity = new ExcelExportEntity("报名时间", "signingUptime", 15); + entity.setFormat("yyyy-MM-dd HH:mm:ss"); + commonEntities.add(entity); + + //线路表头 + ArrayList lineEntities = new ArrayList<>(commonEntities); + lineEntities.add(new ExcelExportEntity("出行时间", "playStartTime", 20)); + lineEntities.add(new ExcelExportEntity("线路名称", "lineName", 20)); + lineEntities.add(new ExcelExportEntity("旅行社", "travelAgencyName", 20)); + lineEntities.add(new ExcelExportEntity("家属人数", "familyCount", 20)); + + //自由组团表头 + ArrayList travelEntities = new ArrayList<>(commonEntities); + travelEntities.add(new ExcelExportEntity("旅行社", "travelAgencyName", 20)); + + commonEntities.add(new ExcelExportEntity("备注", "remark", 30)); + + try { + TherapyDownload.excelResponse(response, "人员名单.xlsx"); + if(Arrays.asList(types).contains("line")) { + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, lineEntities, lineEnroll); + workbook.write(response.getOutputStream()); + } + if(Arrays.asList(types).contains("travel")) { + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, travelEntities, travelEnroll); + workbook.write(response.getOutputStream()); + } + } catch (Exception e) { + log.error(e.getMessage()); + } + } + + /** + * 导出查询字段白名单映射。 + * + * @param searchName 前端查询字段,仅支持 userName(姓名)和 loginName(一卡通号) + * @return 带报名表别名的数据库字段;返回空字符串表示不追加模糊查询条件 + */ + private String getEnrollSearchColumn(String searchName) { + if ("userName".equals(searchName)) { + return "enroll.userName"; + } + if ("loginName".equals(searchName)) { + return "enroll.loginName"; + } + return ""; + } + + @At + @Ok("void") + @ViReturn + @SaCheckLogin + public void doExport(@Param(value = "regionalNature", required = false) String regionalNature, + @Param(value = "state", required = false) Integer state, + @Param(value = "searchName", required = false) String searchName, + @Param(value = "searchKeyword", required = false) String searchKeyword, + @Param(value = "startYear", required = false) Integer startYear, + @Param(value = "endYear", required = false) Integer endYear, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "unitId", required = false) String unitId, + @Param(value = "takePartInLineId", required = false) String takePartInLineId, + @Param(value = "agencyId", required = false) String agencyId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "takePartInBaseManagementId", required = false) String takePartInBaseManagementId, + @Param(value = "signUpMode", required = false) String signUpMode, + @Param(value = "isTakePartIn", required = false) Integer isTakePartIn, + @Param(value = "types", required = false) String[] types, + @Param(value = "satisfyPeople", required = false) Boolean satisfyPeople, + HttpServletResponse response) throws IOException { + + response.setContentType("application/octet-stream"); + response.setHeader("content-disposition", "attachment;filename=" + + URLEncoder.encode("疗休养报名人员名单.zip", StandardCharsets.UTF_8)); + + Cnd commonCnd = Cnd.NEW(); + if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) { + commonCnd.and(Cnd.likeEX(searchName, searchKeyword)); + } + if (!TherapyContext.hasAnyRoles("sysadmin, A06")) { + commonCnd.and(Cnd.exps("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()).or("enroll.selfUnionId", "=", TherapyContext.getUnionId())); + } + commonCnd.and("enroll.isNormal", "=", true); + commonCnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + + //线路的查询 + Sql lineSql = Sqls.create(""" + SELECT + line.regionalNature, + lxs.travelAgencyName, + line.lineName, + lineu.signUpMode, + un.unionname AS selectUnionName, + enroll.*, + bed.bedType, + bed.bedNum, + bed.otherSleepUser, + date_format( enroll.signingUptime, '%Y-%m-%d %H:%i:%s' ) signingUptimeFormat, + date_format( lineu.playStartTime, '%Y-%m-%d' ) playStartTime, + lineu.lineId, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id) familyCount, + u.schoolTime + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_user` u on enroll.loginName = u.loginname + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_union un ON un.id = lineu.unionId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = IFNULL(lineu.travelAgencyId, line.travelAgencyId) + LEFT JOIN staff_therapy_enroll_bed bed ON bed.id = enroll.bedInfoId + $condition + """); + Cnd lineCnd = commonCnd.clone(); + lineCnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + lineCnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + lineCnd.andEX("enroll.selfUnitId", "=", unitId); + lineCnd.andEX("line.id", "=", takePartInLineId); + lineCnd.andEX("line.regionalNature", "=", regionalNature); + lineCnd.andEX("lineu.signUpMode", "=", signUpMode); + addLineTravelAgencyCondition(lineCnd, agencyId); + lineCnd.andEX("enroll.selfUnionId", "=", unionId); + lineCnd.andEX("enroll.isTakePartIn", "=", isTakePartIn); + lineCnd.and("enroll.takePartInLineId", "is not", null); + lineCnd.and("enroll.takePartInLineId", "!=", ""); + + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + lineCnd.and(seg); + } + lineCnd.asc("playStartTime").asc("unionName"); + lineSql.setCondition(lineCnd); + List lineEnroll = baseService.listMap(lineSql); + + if (satisfyPeople) { + //按照选择线路id分组,便于判断是否成团 + Map> enrollGroup = lineEnroll.stream().collect(Collectors.groupingBy(o -> o.getString("takePartInLineId"))); + + List unionSelects = + baseService.dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("enable", "=", true)); + Map selectMap = unionSelects.stream().collect(Collectors.toMap(TheRapyRecuperationLineUnionSelect::getId, o -> o)); + + lineEnroll = enrollGroup.entrySet().stream() + .filter(entry -> selectMap.containsKey(entry.getKey()) && (entry.getValue().size() + entry.getValue().stream().mapToInt(o -> o.getInt("familyCount")).sum()) >= selectMap.get(entry.getKey()).getEstimatedFamilyNumbers()) + .flatMap(entry -> entry.getValue().stream()) + .collect(Collectors.toList()); + } + + //自由组团的查询 + Sql travelSql = Sqls.create(""" + SELECT + enroll.*, + bed.bedType, + bed.bedNum, + bed.otherSleepUser, + lxs.travelAgencyName, + u.schoolTime + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_user` u on enroll.loginName = u.loginname + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = enroll.takePartInTravelAgencyId + LEFT JOIN staff_therapy_enroll_bed bed ON bed.id = enroll.bedInfoId + $condition + """); + Cnd travelCnd = commonCnd.clone(); + travelCnd.andEX("enroll.selfUnionId", "=", unionId); + travelCnd.andEX("lxs.`year`", ">=", startYear); + travelCnd.andEX("lxs.`year`", "<=", endYear); + travelCnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + travelCnd.andEX("enroll.isTakePartIn", "=", isTakePartIn); + travelCnd.and("enroll.takePartInTravelAgencyId", "is not", null); + travelCnd.and("enroll.takePartInTravelAgencyId", "!=", ""); + travelCnd.desc("enroll.unionName"); + travelSql.setCondition(travelCnd); + List travelEnroll = baseService.listMap(travelSql); + //查询所有的旅行社 + List travelList = baseService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW()); + Map travelMap = travelList.stream().collect(Collectors.toMap(TheRapyRecuperationTravelAgency::getId, TheRapyRecuperationTravelAgency::getTravelAgencyName)); + TheRapyRecuperationConfig config = baseService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + lineEnroll = expandExportCompanionRows(lineEnroll, config); + travelEnroll = expandExportCompanionRows(travelEnroll, config); + // 按选择线路记录分组,避免同一线路被不同分工会选择时导出文件名无法区分所属分工会。 + Map> lineGroupMap = lineEnroll.stream().collect(Collectors.groupingBy(o -> o.getString("takePartInLineId"))); + Map> travelGroupMap = travelEnroll.stream().collect(Collectors.groupingBy(o -> o.getString("takePartInTravelAgencyId"))); + + //公共的导出表头 + ArrayList commonEntities = new ArrayList<>(); + commonEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + commonEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + commonEntities.add(new ExcelExportEntity("性别", "sex", 10)); + commonEntities.add(new ExcelExportEntity("所属单位", "unitName", 20)); + commonEntities.add(new ExcelExportEntity("所属工会", "unionName", 20)); + commonEntities.add(new ExcelExportEntity("身份证号", "idCard", 30)); + commonEntities.add(new ExcelExportEntity("手机号", "mobile", 15)); + if (isCompanionDetailEnabled(config)) { + commonEntities.add(new ExcelExportEntity("与本人关系", "relation", 15)); + } + commonEntities.add(new ExcelExportEntity("床型", "bedType", 20)); + commonEntities.add(new ExcelExportEntity("床位数", "bedNum", 20)); + commonEntities.add(new ExcelExportEntity("意向拼房人", "otherSleepUser", 20)); + ExcelExportEntity entity = new ExcelExportEntity("报名时间", "signingUptime", 15); + entity.setFormat("yyyy-MM-dd HH:mm:ss"); + commonEntities.add(entity); + + //线路表头 + ArrayList lineEntities = new ArrayList<>(commonEntities); + lineEntities.add(new ExcelExportEntity("出行时间", "playStartTime", 20)); + lineEntities.add(new ExcelExportEntity("线路名称", "lineName", 20)); + lineEntities.add(new ExcelExportEntity("旅行社", "travelAgencyName", 20)); + lineEntities.add(new ExcelExportEntity("家属人数", "familyCount", 20)); + + //自由组团表头 + ArrayList travelEntities = new ArrayList<>(commonEntities); + travelEntities.add(new ExcelExportEntity("旅行社", "travelAgencyName", 20)); + + commonEntities.add(new ExcelExportEntity("备注", "remark", 30)); + + ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(response.getOutputStream())); + + try { + if(Arrays.asList(types).contains("line")) { + for (String key : lineGroupMap.keySet()) { + List enrollList = lineGroupMap.get(key); + enrollList.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + String fileName = "线路报名人员/" + buildLineExportFileName(enrollList.get(0)) + ".xlsx"; + zipOutputStream.putNextEntry(new ZipEntry(fileName)); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, lineEntities, enrollList); + workbook.write(zipOutputStream); + zipOutputStream.closeEntry(); + response.flushBuffer(); + } + } + if(Arrays.asList(types).contains("travel")) { + for (String key : travelGroupMap.keySet()) { + List enrollList = travelGroupMap.get(key); + enrollList.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + String fileName = "自由组团报名人员/" + travelMap.get(key) + ".xlsx"; + zipOutputStream.putNextEntry(new ZipEntry(fileName)); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, travelEntities, enrollList); + workbook.write(zipOutputStream); + zipOutputStream.closeEntry(); + response.flushBuffer(); + } + } + zipOutputStream.flush(); + zipOutputStream.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * 生成线路导出压缩包内的表格名称。 + * 分工会线路追加所属分工会,校工会线路追加校工会,避免同名线路在压缩包中难以区分来源。 + * + * @param lineData 当前选择线路分组中的任意一条报名数据,需包含lineName、signUpMode、selectUnionName + * @return 已清理路径特殊字符的表格基础名称,不包含.xlsx后缀 + */ + private String buildLineExportFileName(NutMap lineData) { + String lineName = lineData.getString("lineName"); + String suffix = ""; + Integer signUpMode = lineData.getInt("signUpMode"); + if (signUpMode != null && signUpMode == 2) { + suffix = "(校工会)"; + } else if (signUpMode != null && signUpMode == 1 && StrUtil.isNotBlank(lineData.getString("selectUnionName"))) { + suffix = "(所属分工会:" + lineData.getString("selectUnionName") + ")"; + } + return cleanZipEntryFileName(lineName + suffix); + } + + /** + * 清理zip条目文件名中的路径特殊字符,避免线路名称或分工会名称包含斜杠时生成异常目录。 + * + * @param fileName 文件基础名称 + * @return 可作为zip条目名称片段的文件基础名称 + */ + private String cleanZipEntryFileName(String fileName) { + if (StrUtil.isBlank(fileName)) { + return "未命名线路"; + } + return fileName.replaceAll("[\\\\/:*?\"<>|]", "、"); + } + + @At + @Ok("void") + @ViReturn + @SaCheckLogin + public void doExport1(String regionalNature, Integer state, String searchName, String searchKeyword, + Integer startYear, Integer endYear, String unionId, + String unitId, String takePartInLineId, String agencyId, String lotId, + String takePartInBaseManagementId, String signUpMode, + HttpServletResponse response) throws IOException { + + Cnd cnd = Cnd.NEW(); + + if (Strings.isNotBlank(searchName) && Strings.isNotBlank(searchKeyword)) { + cnd.and(Cnd.likeEX(searchName, searchKeyword)); + } + + Sql sql; + if (state != null && state == 2) { + sql = Sqls.create(""" + SELECT + enroll.*, + lxs.travelAgencyName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id AND relation = '亲属' ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = enroll.takePartInTravelAgencyId + $condition + """); + cnd.andEX("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd.andEX("lxs.`year`", ">=", startYear); + cnd.andEX("lxs.`year`", "<=", endYear); + cnd.andEX("enroll.takePartInTravelAgencyId", "=", agencyId); + cnd.and("enroll.takePartInTravelAgencyId", "is not", null); + cnd.and("enroll.takePartInTravelAgencyId", "!=", ""); + } else { + sql = Sqls.create(""" + SELECT + $lotSql, + line.regionalNature, + lxs.travelAgencyName, + line.lineName, + ma.baseName, + enroll.*, + lineu.lineId, + lineu.playStartTime, + lineu.playEndTime, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id AND relation = '亲属' ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id=enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_base_management ma on ma.id = enroll.takePartInBaseManagementId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = line.travelAgencyId + $condition + """); + cnd.andEX("YEAR(enroll.signingUptime)", ">=", startYear); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("line.regionalNature", "=", regionalNature); + cnd.andEX("lineu.signUpMode", "=", signUpMode); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.and("enroll.takePartInLineId", "!=", ""); + if (state == 3) { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = ma.lotId) as lotName"); + cnd.and("enroll.takePartInBaseManagementId", "is not", null); + cnd.andEX("enroll.takePartInBaseManagementId", "=", takePartInBaseManagementId); + } else { + sql.setVar("lotSql", "(select lotName from staff_therapy_lot where id = line.lotId) as lotName"); + cnd.and("enroll.takePartInLineId", "is not", null); + } + if (StrUtil.isNotBlank(lotId)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.lotId", "=", lotId); +// seg.or("agency.lotId", "=", lotId); + seg.or("ma.lotId", "=", lotId); + cnd.and(seg); + } + if (StrUtil.isNotBlank(unionId)) { + cnd.and("enroll.selfUnionId", "=", unionId); + } + } + cnd.and("enroll.isNormal", "=", true); + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.desc("enroll.unionName"); + sql.setCondition(cnd); + + List list = baseService.listMap(sql); + List enrollList = Lang.collection2list(list, TheRapyRecuperationEnroll.class); + + TheRapyRecuperationConfig config = baseService.dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + + enrollList.forEach(v -> { + baseService.dao().fetchLinks(v, "companionList"); + baseService.dao().fetchLinks(v, "bedInfo"); + baseService.dao().fetchLinks(v, "managementInfo"); + if (StrUtil.isNotBlank(v.getLineId())) { + TheRapyRecuperationLine line = baseService.dao().fetch(TheRapyRecuperationLine.class, v.getLineId()); + v.setLineInfo(line); + } + }); + List arrayList = new ArrayList<>(); + String takePartInLineId2 = ""; + String takePartInBaseManagementId2 = ""; + String agencyName = ""; + String lotName = ""; + for (TheRapyRecuperationEnroll v : enrollList) { + if (StrUtil.isNotBlank(v.getTakePartInLineId()) && !v.getTakePartInLineId().equals(takePartInLineId2)) { + TheRapyRecuperationLine line = baseService.dao().fetch(TheRapyRecuperationLine.class, v.getLineId()); + TheRapyRecuperationLineUnionSelect unionSelect = baseService.dao().fetch(TheRapyRecuperationLineUnionSelect.class, v.getTakePartInLineId()); + TheRapyRecuperationLot lot = baseService.dao().fetch(TheRapyRecuperationLot.class, line.getLotId()); + TheRapyRecuperationTravelAgency agency = baseService.dao().fetch(TheRapyRecuperationTravelAgency.class, unionSelect.getTravelAgencyId()); + agencyName = agency.getTravelAgencyName(); + lotName = lot.getLotName(); + } else { + if (StrUtil.isNotBlank(v.getTakePartInBaseManagementId()) && !v.getTakePartInBaseManagementId().equals(takePartInBaseManagementId2)) { + TheRapyRecuperationBaseManagement management = baseService.dao().fetch(TheRapyRecuperationBaseManagement.class, v.getTakePartInBaseManagementId()); + TheRapyRecuperationLot lot = baseService.dao().fetch(TheRapyRecuperationLot.class, management.getLotId()); + TheRapyRecuperationTravelAgency agency = baseService.dao().fetch(TheRapyRecuperationTravelAgency.class, management.getTravelAgencyId()); + agencyName = agency.getTravelAgencyName(); + lotName = lot.getLotName(); + } + } + String finalAgencyName = agencyName; + String finalLotName = lotName; + arrayList.add(new NutMap() {{ + addv("userName", v.getUserName()); + addv("loginName", v.getLoginName()); + addv("sex", v.getSex()); + addv("unitName", v.getUnitName()); + addv("unionName", v.getUnionName()); + addv("idCard", v.getIdCard()); + addv("mobile", v.getMobile()); + addv("relation", "本人"); + addv("familyNumber", v.getFamilyNumber()); + addv("bedType", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getBedType() : null); + addv("bedNum", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getBedNum() : null); + addv("otherSleepUser", Lang.isNotEmpty(v.getBedInfo()) ? v.getBedInfo().getOtherSleepUser() : null); + addv("baseName", Lang.isNotEmpty(v.getManagementInfo()) ? v.getManagementInfo().getBaseName() : v.getLineInfo().getLineName()); + addv("signingUptime", DateUtil.formatDateTime(v.getSigningUptime())); + addv("agencyName", finalAgencyName); + addv("lotName", finalLotName); + addv("bz", v.getUserName()); + }}); + v.getCompanionList().forEach(c -> { + baseService.dao().fetchLinks(c, "bedInfo"); + arrayList.add(new NutMap() {{ + addv("userName", c.getUserName()); + addv("loginName", c.getLoginName()); + addv("sex", c.getSex()); + addv("unitName", null); + addv("unionName", null); + addv("idCard", c.getIdCard()); + addv("mobile", c.getMobile()); + addv("relation", c.getRelation()); + addv("bedType", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getBedType() : null); + addv("bedNum", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getBedNum() : null); + addv("otherSleepUser", Lang.isNotEmpty(c.getBedInfo()) ? c.getBedInfo().getOtherSleepUser() : null); + addv("baseName", Lang.isNotEmpty(v.getManagementInfo()) ? v.getManagementInfo().getBaseName() : v.getLineInfo().getLineName()); + addv("signingUptime", DateUtil.formatDateTime(v.getSigningUptime())); + addv("agencyName", finalAgencyName); + addv("lotName", finalLotName); + addv("bz", v.getUserName()); + }}); + }); + } + + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("姓名", "userName", 20)); + exportEntities.add(new ExcelExportEntity("工号", "loginName", 20)); + exportEntities.add(new ExcelExportEntity("性别", "sex", 10)); + exportEntities.add(new ExcelExportEntity("单位", "unitName", 20)); + exportEntities.add(new ExcelExportEntity("工会", "unionName", 20)); + exportEntities.add(new ExcelExportEntity("身份证号", "idCard", 30)); + exportEntities.add(new ExcelExportEntity("手机号", "mobile", 15)); + if (config.getFamilyInfo() == 2) { + exportEntities.add(new ExcelExportEntity("与本人关系", "relation", 10)); + exportEntities.add(new ExcelExportEntity("床型", "bedType", 20)); + exportEntities.add(new ExcelExportEntity("床位数", "bedNum", 20)); + exportEntities.add(new ExcelExportEntity("意向拼房人", "otherSleepUser", 20)); + } else { + exportEntities.add(new ExcelExportEntity("携带家属数", "familyNumber", 20)); + } + exportEntities.add(new ExcelExportEntity("疗休养时长", "lotName", 20)); + exportEntities.add(new ExcelExportEntity("集中/目的地", "baseName", 20)); + exportEntities.add(new ExcelExportEntity("旅行社", "agencyName", 20)); + exportEntities.add(new ExcelExportEntity("报名时间", "signingUptime", 20)); + exportEntities.add(new ExcelExportEntity("备注", "bz", 20)); + + try { + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + new String(("报名人员.xls").getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1)); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), exportEntities, arrayList); + workbook.write(response.getOutputStream()); + workbook.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + @At + @ViReturn + @SaCheckLogin + public Object doReimbursement(@Param("data") String data) { + JSONArray objects = JSONUtil.parseArray(data); + List enrollIds = objects.toList(String.class); + if (Lang.isNotEmpty(enrollIds)) { + baseService.dao().update(TheRapyRecuperationEnroll.class, Chain.make("isReimbursement", 1), Cnd.where("id", "in", enrollIds)); + } + return null; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationLineStatisticsController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationLineStatisticsController.java new file mode 100644 index 0000000..b9e88a2 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationLineStatisticsController.java @@ -0,0 +1,501 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.statistics; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.result.Result; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionLineNumberStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import lombok.extern.slf4j.Slf4j; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * @version 1.0 + * @Author zzr + * @name:TheRapyRecuperationStatisticsController + * @Date 2024/6/3 17:32 + * @注释 查看报名情况 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/statistics") +@Ok("json:full") +@Slf4j +public class TheRapyRecuperationLineStatisticsController { + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + @Inject + private TherapyMessage msgApi; + + @Inject + private Dao dao; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html") + @SaCheckPermission("staffTherapyRecuperation.statistics") + public void index() { + } + + @At("/unionLineNumberStatistics") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html") + @SaCheckPermission("staffTherapyRecuperation.unionLineNumberStatistics") + public void unionLineNumberStatistics() { + } + + /** + * 查询基础设置中各分工会配置的线路最低数量,以及当前年度已选择的省内、省外出行时间段数量。 + * + * @param unionId 分工会 ID;为空时查询基础设置中所有已配置分工会 + * @return 分工会线路数量统计 VO 列表,finished 表示省内、省外均达到最低数量要求 + */ + @At("/unionLineNumberStatistics/pageData") + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.unionLineNumberStatistics") + public Object unionLineNumberStatisticsPageData(@Param(value = "unionId", required = false) String unionId) { + TheRapyRecuperationConfig config = dao.fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + List lineNumberConfigs = Optional.ofNullable(config) + .map(TheRapyRecuperationConfig::getUnionLineNumberConfigs) + .orElse(Collections.emptyList()); + if (Strings.isNotBlank(unionId)) { + lineNumberConfigs = lineNumberConfigs.stream() + .filter(item -> unionId.equals(item.getString("unionId"))) + .collect(Collectors.toList()); + } + if (lineNumberConfigs.isEmpty()) { + return new ArrayList<>(); + } + + List unionIds = lineNumberConfigs.stream() + .map(item -> item.getString("unionId")) + .filter(Strings::isNotBlank) + .distinct() + .collect(Collectors.toList()); + if (unionIds.isEmpty()) { + return new ArrayList<>(); + } + Map unionNameMap = dao.query(TherapyUnion.class, Cnd.where("id", "in", unionIds)) + .stream() + .collect(Collectors.toMap(TherapyUnion::getId, TherapyUnion::getUnionname)); + + Sql selectedSql = Sqls.create(""" + SELECT + us.unionId, + line.regionalNature, + COUNT(us.id) AS selectedNumber + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + WHERE + us.signUpMode = 1 + AND YEAR(us.selectTime) = @year + GROUP BY + us.unionId, + line.regionalNature + """); + selectedSql.setParam("year", DateUtil.thisYear()); + List selectedList = (List) enrollService.listMap(selectedSql); + Map selectedNumberMap = new HashMap<>(); + for (NutMap selected : selectedList) { + selectedNumberMap.put(selected.getString("unionId") + "#" + selected.getString("regionalNature"), + Optional.ofNullable(selected.getInt("selectedNumber")).orElse(0)); + } + + List resultList = new ArrayList<>(); + for (NutMap lineNumberConfig : lineNumberConfigs) { + String rowUnionId = lineNumberConfig.getString("unionId"); + Integer provinceOutNumber = Optional.ofNullable(lineNumberConfig.getInt("minProvinceOutNumber")).orElse(0); + Integer provinceInNumber = Optional.ofNullable(lineNumberConfig.getInt("minProvinceInNumber")).orElse(0); + Integer selectedProvinceOutNumber = selectedNumberMap.getOrDefault(rowUnionId + "#" + TheRapyRecuperationProvinceType.provinceOut.getValue(), 0); + Integer selectedProvinceInNumber = selectedNumberMap.getOrDefault(rowUnionId + "#" + TheRapyRecuperationProvinceType.provinceIn.getValue(), 0); + boolean finished = selectedProvinceOutNumber >= provinceOutNumber && selectedProvinceInNumber >= provinceInNumber; + + // 配置来源于基础设置 JSON,统计结果按当前年度分工会已选择出行时间段数量合并展示。 + resultList.add(new UnionLineNumberStatisticsVo() + .setUnionId(rowUnionId) + .setUnionName(unionNameMap.getOrDefault(rowUnionId, "")) + .setProvinceOutNumber(provinceOutNumber) + .setProvinceInNumber(provinceInNumber) + .setSelectedProvinceOutNumber(selectedProvinceOutNumber) + .setSelectedProvinceInNumber(selectedProvinceInNumber) + .setFinished(finished)); + } + return resultList; + } + + /** + * 统计线路报名情况列表。 + * + * @param pageForm 分页参数,包含 pageNumber、pageSize、排序字段等表格通用参数 + * @param startYear 选择线路年度开始年份,按 lineu.selectTime 年份过滤 + * @param endYear 选择线路年度结束年份,按 lineu.selectTime 年份过滤 + * @param unionId 分工会 ID,管理员可传;普通分工会账号按当前登录人分工会过滤 + * @param takePartInLineId 线路 ID,对应 staff_therapy_line.id + * @param lotId 标段 ID,对应 staff_therapy_lot.id + * @param signUpMode 报名模式,1 分工会组织,2 校工会组织 + * @param selectId 线路选择记录 ID,保留给旧入口按具体出行时间段精确筛选 + * @param playMonth 出行年月,格式 yyyy-MM,按 lineu.playStartTime 所属年月筛选 + * @param regionalNature 线路类型,省内或省外 + * @param travelAgencyId 旅行社 ID,同时匹配线路选择记录和线路主表上的旅行社字段 + * @return 分页数据,data.list 为线路统计行,data.totalCount 为总条数 + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.statistics") + public Object pageData(PageForm pageForm, + @Param(value = "startYear", required = false) Integer startYear, + @Param(value = "endYear", required = false) Integer endYear, + @Param(value = "unionId", required = false) String unionId, + @Param("takePartInLineId") String takePartInLineId, + @Param(value = "lotId", required = false) String lotId, + @Param(value = "signUpMode", required = false) String signUpMode, + @Param(value = "selectId", required = false) String selectId, + @Param(value = "playMonth", required = false) String playMonth, + @Param(value = "regionalNature", required = false) String regionalNature, + @Param(value = "travelAgencyId", required = false) String travelAgencyId) { + Sql sql = Sqls.create(""" + SELECT + line.id, + line.lineName, + line.regionalNature, + lineu.lineId, + lineu.id as lineUId, + lineu.signUpMode, + lineu.minimumGroupSize, + lineu.estimatedFamilyNumbers, + YEAR(lineu.selectTime) as `year`, + CONCAT(DATE_FORMAT(lineu.playStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.playEndTime,'%m月%d日')) AS linePlayTime, + CONCAT(DATE_FORMAT(lineu.signUpStartTime,'%m月%d日'),'-',DATE_FORMAT(lineu.signUpEndTime,'%m月%d日')) AS signUpTime, + DATE_FORMAT(lineu.adjustSignUpEndTime, '%Y-%m-%d %H:%i') AS adjustSignUpEndTime, + lineu.playStartTime as playStartTime1, + lineu.playEndTime as playEndTime2, + IFNULL(usTa.travelAgencyName, lineTa.travelAgencyName) AS travelAgencyName, + IFNULL(usTa.contact, lineTa.contact) AS contact, + IFNULL(usTa.contactMobileNumber, lineTa.contactMobileNumber) AS contactMobileNumber, + enrollStats.usUnionId, + if(lineu.signUpMode = 2, '校工会', un.unionname) as unionname, + lot.lotName, + lot.lotValue, + enrollStats.familyNumber, + IFNULL(enrollStats.lineNum, 0) lineNum, + IFNULL(enrollStats.signUpUserFamilyNum, 0) as signUpUserFamilyNum, + IFNULL(enrollStats.adultFamilyNum, 0) as adultFamilyNum + FROM + staff_therapy_line_union_select lineu + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + LEFT JOIN staff_therapy_travel_agency usTa ON lineu.travelAgencyId = usTa.id + LEFT JOIN staff_therapy_travel_agency lineTa ON line.travelAgencyId = lineTa.id + LEFT JOIN staff_therapy_union un ON un.id = lineu.unionId + LEFT JOIN ( + SELECT + e.takePartInLineId, + MAX(e.takePartInUnionId) AS usUnionId, + MAX(e.familyNumber) AS familyNumber, + COUNT(DISTINCT e.id) AS lineNum, + COUNT(c.id) AS signUpUserFamilyNum, + SUM(CASE WHEN c.age >= 18 THEN 1 ELSE 0 END) AS adultFamilyNum + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_enroll_companion c ON c.trreId = e.id + WHERE + e.stateId = 2750 + AND e.isNormal = TRUE + $unionCnd + GROUP BY + e.takePartInLineId + ) enrollStats ON enrollStats.takePartInLineId = lineu.id + $condition + ORDER BY line.serialNumber ASC, lineu.playStartTime ASC + """); + Sql countSql = Sqls.create(""" + SELECT + COUNT(1) + FROM + staff_therapy_line_union_select lineu + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_lot lot ON lot.id = line.lotId + $condition + """); + Cnd cnd = Cnd.NEW(); + if (startYear != null) { + cnd.and("lineu.selectTime", ">=", startYear + "-01-01 00:00:00"); + } + if (endYear != null) { + cnd.and("lineu.selectTime", "<", (endYear + 1) + "-01-01 00:00:00"); + } + cnd.andEX("lineu.signUpMode", "=", signUpMode); + sql.setVar("unionCnd", ""); + if (!TherapyContext.hasAnyRoles("sysadmin,H06")) { + String unionCndSql = "and (e.selfUnionId='%s' or e.takePartInUnionId = '%s')".formatted(TherapyContext.getUnionId(), TherapyContext.getUnionId()); + sql.setVar("unionCnd", unionCndSql); + cnd.and("lineu.unionId", "=", TherapyContext.getUnionId()); + } else { + if (Strings.isNotBlank(unionId)) { + cnd.and("lineu.unionId", "=", unionId); + } + } + + cnd.andEX("line.lotId", "=", lotId); + cnd.andEX("line.id", "=", takePartInLineId); + cnd.andEX("lineu.id", "=", selectId); + // 出行年月筛选按出行开始时间归属月份统计,跨月线路归入开始月份。 + if (Strings.isNotBlank(playMonth)) { + String playMonthStart = playMonth + "-01 00:00:00"; + String playMonthEnd = DateUtil.offsetMonth(DateUtil.parse(playMonth + "-01", "yyyy-MM-dd"), 1).toDateStr() + " 00:00:00"; + cnd.and("lineu.playStartTime", ">=", playMonthStart); + cnd.and("lineu.playStartTime", "<", playMonthEnd); + } + cnd.andEX("line.regionalNature", "=", regionalNature); + addTravelAgencyCondition(cnd, travelAgencyId); + sql.setCondition(cnd); + countSql.setCondition(cnd); + return enrollService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql, countSql); + } + + /** + * 统计页按旅行社过滤线路选择记录。 + * 旅行社可能保存在线路选择记录或线路主表,两个字段任一命中都应纳入统计结果。 + * + * @param cnd 当前统计查询条件 + * @param travelAgencyId 旅行社 ID,为空时不增加过滤条件 + */ + private void addTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + + /** + * 根据线路查询报名详情 + * + * @param searchKeyword + * @param unionId + * @param unitId + * @return + */ + @At + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.statistics") + public Object getUserDateByLine(PageForm pageForm, + @Param(value = "takePartLineId", required = false) String takePartLineId, + @Param(value = "searchKeyword", required = false) String searchKeyword, + @Param(value = "unionId", required = false) String unionId, + @Param(value = "unitId", required = false) String unitId) { + Sql sql = Sqls.create(""" + SELECT + enroll.*, + line.lineName, + line.id as lineId, + line.regionalNature, + '教职工' userNature, + state.stateColor, + state.stateName, + CONCAT(DATE_FORMAT(rs.playStartTime,'%m月%d日'),'-',DATE_FORMAT(rs.playEndTime,'%m月%d日')) AS linePlayTime, + IF + ( enroll.takePartInUnionId != enroll.selfUnionId, TRUE, FALSE ) isTransferIn, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) isFamily, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id ) num + FROM + `staff_therapy_enroll` enroll + LEFT JOIN `staff_therapy_line_union_select` rs ON rs.id = enroll.takePartInLineId + LEFT JOIN `staff_therapy_line` line on line.id=rs.lineId + LEFT JOIN staff_therapy_audit_state state ON state.stateId = enroll.stateId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("enroll.takePartInLineId", "=", takePartLineId); + cnd.and("enroll.stateId", "=", 2750); + cnd.andEX("enroll.selfUnionId", "=", unionId); + cnd.andEX("enroll.selfUnitId", "=", unitId); + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.andEX("enroll.isNormal", "=", true); + if (StrUtil.isNotBlank(searchKeyword)) { + cnd.and(Cnd.exps("enroll.loginName", "like", "%" + searchKeyword + "%").or("enroll.userName", "like", "%" + searchKeyword + "%")); + } + cnd.desc("enroll.signingUptime"); + cnd.desc("enroll.unitName"); + sql.setCondition(cnd); + return enrollService.listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @At + @ViReturn + @SaCheckLogin + public Object sendSuccess(String id) { + + TheRapyRecuperationLineUnionSelect unionSelect = dao.fetch(TheRapyRecuperationLineUnionSelect.class, id); + TheRapyRecuperationLine line = dao.fetch(TheRapyRecuperationLine.class, unionSelect.getLineId()); + if (DateUtil.compare(new Date(), unionSelect.getSignUpEndTime()) < 0) { + return Result.error("报名还未结束,不能发送"); + } + //找出报名人员 + List enrolls = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", id) + .and("isNormal", "=", true).and("year(signingUptime)", "=", DateUtil.thisYear()) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL))); + + //发短信 + enrolls.forEach(item -> { + String content = "%s老师,您好!您报名的%s线路,出行时间为%s,达到成团条件,请准时参加疗休养活动。".formatted( + item.getUserName(), + line.getLineName(), + DateUtil.format(unionSelect.getPlayStartTime(), "yyyy-MM-dd") + ); + List list = List.of(Map.of("type", "User", "userId", item.getLoginName(), "name", item.getUserName())); + msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", TherapyMessage.sendMode.normal.name()); + }); + return null; + } + + @At + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + public Object sendFail(String id) { + TheRapyRecuperationLineUnionSelect unionSelect = dao.fetch(TheRapyRecuperationLineUnionSelect.class, id); + TheRapyRecuperationLine line = dao.fetch(TheRapyRecuperationLine.class, unionSelect.getLineId()); + if (DateUtil.compare(new Date(), unionSelect.getSignUpEndTime()) < 0) { + return Result.error("报名还未结束,不能发送"); + } + //找出报名人员 + List enrolls = dao.query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", id) + .and("isNormal", "=", true).and("delFlag", "=", false).and("year(signingUptime)", "=", DateUtil.thisYear()) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL))); + + //发短信 + enrolls.forEach(item -> { + String content = "%s老师,您好!您报名的%s线路,出行时间为%s,因报名人数不足未达到成团条件,请尽快进入疗休养管理系统重新选择线路,7月份线路报名截止时间延长至7月4日晚上24点,谢谢!".formatted( + item.getUserName(), + line.getLineName(), + DateUtil.format(unionSelect.getPlayStartTime(), "yyyy-MM-dd") + ); + List list = List.of(Map.of("type", "User", "userId", item.getLoginName(), "name", item.getUserName())); + msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", TherapyMessage.sendMode.normal.name()); + }); + + // 未成团通知统一保留报名数据,只将报名标记为非正常且已删除,便于后续调剂和历史追溯。 + List idList = enrolls.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList()); + dao.update(TheRapyRecuperationEnroll.class, Chain.make("isNormal", false).add("delFlag", true), Cnd.where("id", "in", idList)); + return null; + } + + /** + * 补发 2026 年已删除报名记录的未成团通知。 + * 仅 superadmin 可操作,避免普通统计人员误触发批量补发。 + * + * @return 补发触发数量,前端展示给操作人确认 + */ + @At("/resendFailNotice") + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + public Object resendFailNotice() { + Object loginName = TherapyContext.getPrincipalProperty("loginname"); + if (!"superadmin".equals(Strings.sNull(loginName))) { + return Result.error("仅 superadmin 可操作"); + } + int count = enrollService.resendDeletedFailNotice(2026); + return Result.success("已触发补发未成团通知" + count + "条"); + } + + /** + * 手动发送所选线路的成团邮件给旅行社。 + * 参数 lineUnionSelectIds 为统计页勾选的线路选择记录 ID 数组;返回值为统一 Result,msg 中说明实际发送邮件的旅行社数量。 + * + * @param lineUnionSelectIds 线路选择记录 ID,对应 staff_therapy_line_union_select.id + * @return Result,code=0 表示触发完成,msg 展示发送结果 + */ + @At("/sendGroupMail") + @ViReturn + @SaCheckLogin + public Object sendGroupMail(@Param("lineUnionSelectIds") String[] lineUnionSelectIds) { + Object loginName = TherapyContext.getPrincipalProperty("loginname"); + if (!"superadmin".equals(Strings.sNull(loginName))) { + return Result.error("仅 superadmin 可操作"); + } + if (Lang.isEmpty(lineUnionSelectIds)) { + return Result.error("请选择需要发送成团邮件的线路"); + } + int count = enrollService.sendTakePartInUserByLineMail(Arrays.asList(lineUnionSelectIds)); + return Result.success("已发送成团邮件" + count + "封"); + } + + /** + * 统计页一键统赋勾选线路的报名、出行和调剂时间。 + * + * @param lineUnionSelectIds 统计页勾选的线路选择记录 ID,对应 staff_therapy_line_union_select.id + * @param lineUnionSelects 统赋时间表单数组,当前只取第一项作为批量更新模板 + * @return 空数据,前端根据统一返回包装判断是否成功 + */ + @At("/setGiveLineTimes") + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.statistics") + @Aop(TransAop.READ_COMMITTED) + public Object setGiveLineTimes(@Param("lineUnionSelectIds") String[] lineUnionSelectIds, + @Param("lineUnionSelects") TheRapyRecuperationLineUnionSelect[] lineUnionSelects) { + if (Lang.isEmpty(lineUnionSelectIds) || Lang.isEmpty(lineUnionSelects)) { + return null; + } + TheRapyRecuperationLineUnionSelect lineUnionSelect = lineUnionSelects[0]; + Chain chain = Chain.make("enable", Boolean.TRUE.equals(lineUnionSelect.getEnable())); + if (lineUnionSelect.getSignUpStartTime() != null) { + chain.add("signUpStartTime", lineUnionSelect.getSignUpStartTime()); + } + if (lineUnionSelect.getSignUpEndTime() != null) { + chain.add("signUpEndTime", lineUnionSelect.getSignUpEndTime()); + } + if (lineUnionSelect.getChangeEndTime() != null) { + chain.add("changeEndTime", lineUnionSelect.getChangeEndTime()); + } + if (lineUnionSelect.getPlayStartTime() != null) { + chain.add("playStartTime", lineUnionSelect.getPlayStartTime()); + } + if (lineUnionSelect.getPlayEndTime() != null) { + chain.add("playEndTime", lineUnionSelect.getPlayEndTime()); + } + if (lineUnionSelect.getAdjustSignUpEndTime() != null) { + chain.add("adjustSignUpEndTime", lineUnionSelect.getAdjustSignUpEndTime()); + } + dao.update(TheRapyRecuperationLineUnionSelect.class, chain, Cnd.where("id", "in", lineUnionSelectIds)); + return null; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationTravelAgencyMonthlyStatisticsController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationTravelAgencyMonthlyStatisticsController.java new file mode 100644 index 0000000..2663e9e --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/statistics/TheRapyRecuperationTravelAgencyMonthlyStatisticsController.java @@ -0,0 +1,177 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.statistics; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.enmus.ExcelType; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyDownload; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.TravelAgencyMonthlyEnrollStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionEnrollStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import org.apache.poi.ss.usermodel.Workbook; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.mvc.annotation.Param; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 旅行社月度报名统计。 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/travelAgencyMonthlyStatistics") +@Ok("json:full") +public class TheRapyRecuperationTravelAgencyMonthlyStatisticsController { + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html") + @SaCheckPermission("staffTherapyRecuperation.travelAgencyMonthlyStatistics") + public void index() { + } + + /** + * 查询指定年度各旅行社每月报名数量。 + * 参数 year 为统计年度,前端年度选择器传 yyyy;为空时默认当前年度。 + * 返回值为 List,每项包含旅行社、月份和报名数量。 + * + * @param year 统计年度 + * @return 旅行社月度报名数量统计列表 + */ + @At("/getChartData") + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.travelAgencyMonthlyStatistics") + public Object getChartData(@Param(value = "year", required = false) Integer year) { + Integer queryYear = year == null ? DateUtil.thisYear() : year; + return enrollService.getTravelAgencyMonthlyEnrollStatistics(queryYear); + } + + /** + * 查询指定年度二级工会出去疗休养人数。 + * 参数 year 为统计年度,前端年度选择器传 yyyy;为空时默认当前年度。 + * 返回值为 List,每项包含二级工会、月份和有效报名人数。 + * + * @param year 统计年度 + * @return 二级工会月度出行人数统计列表 + */ + @At("/getUnionChartData") + @ViReturn + @SaCheckPermission("staffTherapyRecuperation.travelAgencyMonthlyStatistics") + public Object getUnionChartData(@Param(value = "year", required = false) Integer year) { + Integer queryYear = year == null ? DateUtil.thisYear() : year; + List list = enrollService.getUnionEnrollStatistics(queryYear); + return list; + } + + /** + * 导出当前年度旅行社月度报名统计。 + * 参数 year 为统计年度;为空时默认当前年度。 + * 返回 xlsx 文件,列为年度、旅行社和动态月份数量列。 + * + * @param year 统计年度 + * @param response HTTP 响应对象,方法直接写出 Excel 文件 + */ + @At("/doExportExcel") + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.travelAgencyMonthlyStatistics") + public void doExportExcel(@Param(value = "year", required = false) Integer year, + HttpServletResponse response) throws IOException { + Integer queryYear = year == null ? DateUtil.thisYear() : year; + NutMap exportData = enrollService.getTravelAgencyMonthlyEnrollExportData(queryYear); + List months = getExportMonths(exportData); + List list = getExportRows(exportData); + + ArrayList exportEntities = buildMonthExportEntities("旅行社", "travelAgencyName", months); + + TherapyDownload.excelResponse(response, queryYear + "旅行社月度报名统计.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list); + workbook.write(response.getOutputStream()); + workbook.close(); + } + + /** + * 导出当前年度二级工会出去疗休养人数统计。 + * 参数 year 为统计年度;为空时默认当前年度。 + * 返回 xlsx 文件,列为年度、二级工会和动态月份数量列。 + * + * @param year 统计年度 + * @param response HTTP 响应对象,方法直接写出 Excel 文件 + */ + @At("/doExportUnionExcel") + @Ok("void") + @SaCheckPermission("staffTherapyRecuperation.travelAgencyMonthlyStatistics") + public void doExportUnionExcel(@Param(value = "year", required = false) Integer year, + HttpServletResponse response) throws IOException { + Integer queryYear = year == null ? DateUtil.thisYear() : year; + NutMap exportData = enrollService.getUnionEnrollExportData(queryYear); + List months = getExportMonths(exportData); + List list = getExportRows(exportData); + + ArrayList exportEntities = buildMonthExportEntities("二级工会", "unionName", months); + + TherapyDownload.excelResponse(response, queryYear + "二级工会月度疗休养出行人数统计.xlsx"); + ExportParams exportParams = new ExportParams(); + exportParams.setType(ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, exportEntities, list); + workbook.write(response.getOutputStream()); + workbook.close(); + } + + /** + * 根据有数据的月份生成横向月份导出列。 + * 固定列为年度和统计对象名称,动态列为 7月、8月 等,字段名为 month_7、month_8。 + * + * @param nameTitle 统计对象列标题,例如旅行社、二级工会 + * @param nameField 统计对象列字段,例如 travelAgencyName、unionName + * @param months 有数据的月份数字列表,按月份升序生成列 + * @return Excel 导出列定义 + */ + private ArrayList buildMonthExportEntities(String nameTitle, String nameField, List months) { + ArrayList exportEntities = new ArrayList<>(); + exportEntities.add(new ExcelExportEntity("年度", "year", 15)); + exportEntities.add(new ExcelExportEntity(nameTitle, nameField, 35)); + months.forEach(month ->{ + ExcelExportEntity entity = new ExcelExportEntity(month + "月", "month_" + month, 15); + entity.setType(10); + exportEntities.add(entity); + } ); + return exportEntities; + } + + /** + * 从 service 返回的导出数据中读取动态月份列表。 + * months 字段为 List,用于按实际有数据的月份生成 Excel 列。 + * + * @param exportData service 构建的导出数据 + * @return 有数据的月份数字列表 + */ + @SuppressWarnings("unchecked") + private List getExportMonths(NutMap exportData) { + return (List) exportData.get("months"); + } + + /** + * 从 service 返回的导出数据中读取 Excel 行数据。 + * rows 字段为 List,每行包含年度、统计对象名称以及 month_月份 数量字段。 + * + * @param exportData service 构建的导出数据 + * @return Excel 行数据 + */ + @SuppressWarnings("unchecked") + private List getExportRows(NutMap exportData) { + return (List) exportData.get("rows"); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/theRapyConfig/TheRapyRecuperationConfigController.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/theRapyConfig/TheRapyRecuperationConfigController.java new file mode 100644 index 0000000..e79e559 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/controller/theRapyConfig/TheRapyRecuperationConfigController.java @@ -0,0 +1,144 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.theRapyConfig; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.ViReturn; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot; +import cn.dev33.satoken.annotation.SaCheckLogin; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.json.Json; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; +import org.nutz.mvc.annotation.At; +import org.nutz.mvc.annotation.Ok; +import org.nutz.trans.Trans; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * rapy休养配置控制器 + * + * @author zhf + * @date 2022/06/01 + */ +@IocBean +@At("/platform/staffTherapyRecuperation/TheRapyConfig") +@Ok("json:full") +public class TheRapyRecuperationConfigController { + + + @Inject + private Dao dao; + + + @At("") + @Ok("beetl:/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html") + @SaCheckPermission("staffTherapyRecuperation.TheRapyConfig") + public void index() { + } + + /** + * 保存疗休养配置。 + * + * @param config 配置主体,包含基本配置、服务须知以及标段列表等页面表单字段 + * @param lotDeleteList 需要删除的标段 ID 数组,后台会按 ID 清理标段数据 + * @param unionLineNumberConfigs 分工会线路数量配置 JSON 数组,元素包含 unionId、minProvinceOutNumber、minProvinceInNumber + * @return ViReturn 统一包装的 JSON 结果,保存成功时 data 为空 + */ + @At + @ViReturn + @SaCheckLogin + @Aop(TransAop.READ_COMMITTED) + public Object operation(TheRapyRecuperationConfig config, String[] lotDeleteList, String unionLineNumberConfigs) { + // unionLineNumberConfigs 为前端分工会线路数量配置 JSON 数组,返回保存后的配置对象仍由 findOne 接口按实体结构回显。 + config.setUnionLineNumberConfigs(Strings.isBlank(unionLineNumberConfigs) + ? new ArrayList<>() + : Json.fromJsonAsList(NutMap.class, unionLineNumberConfigs)); + if (Strings.isNotBlank(config.getId())) { + if (Lang.isNotEmpty(lotDeleteList)) { + dao.clear(TheRapyRecuperationLot.class, Cnd.where("id", "in", lotDeleteList)); + } + dao.updateWith(config, "lots"); + List collect = config.getLots().stream().filter(v -> v.getConfigId() == null).collect(Collectors.toList()); + for (TheRapyRecuperationLot obj : collect) { + obj.setConfigId(config.getId()); + } + dao.insert(collect); + } else { + dao.insertWith(config, "lots"); + } + return null; + } + + @At + @ViReturn + @SaCheckLogin + public Object findOne() { + return dao.fetchLinks(dao.fetch(TheRapyRecuperationConfig.class), "lots",Cnd.NEW().desc("lotValue")); + } + + + /** + * 查使用该标段的线路和目的地 + * @param lotId + * @return + */ + @At + @ViReturn + @SaCheckLogin + public Object getLotsById(String lotId){ + List lineNames = new ArrayList<>(); + List baseNames = new ArrayList<>(); + Map> map = new HashMap<>(); + List lineList = dao.query(TheRapyRecuperationLine.class, Cnd.where("lotId", "=", lotId)); + if (!CollectionUtils.isEmpty(lineList)){ + lineList.forEach(v-> lineNames.add(v.getLineName())); + map.put("line",lineNames); + } + List managementList = dao.query(TheRapyRecuperationBaseManagement.class, Cnd.where("lotId", "=", lotId)); + if (!CollectionUtils.isEmpty(managementList)){ + managementList.forEach(v-> baseNames.add(v.getBaseName())); + map.put("base",baseNames); + } + return map; + } + + + /** + * 强制删除标段时长,会删除已绑定的线路和目的地 + * @param lotId + * @return + */ + @At + @ViReturn + @SaCheckLogin + public Object deleteLotById(String lotId){ + Trans.exec(()->{ + dao.clear(TheRapyRecuperationLot.class, Cnd.where("id","=",lotId)); + List lineList = dao.query(TheRapyRecuperationLine.class, Cnd.where("lotId", "=", lotId)); + if (!CollectionUtils.isEmpty(lineList)) { + lineList.forEach(v -> v.setLotId(null)); + dao.update(lineList); + } + List managementList = dao.query(TheRapyRecuperationBaseManagement.class, Cnd.where("lotId", "=", lotId)); + if (!CollectionUtils.isEmpty(managementList)) { + managementList.forEach(v -> v.setLotId(null)); + dao.update(managementList); + } + }); + return null; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByLineJob.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByLineJob.java new file mode 100644 index 0000000..3077089 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByLineJob.java @@ -0,0 +1,145 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.job; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import org.apache.poi.ss.usermodel.Workbook; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @Author: JyuHsin + * @Date: 2024/6/14 10:41 + * @Version: v1.0.0 + * @Description: 给旅游社发送线路成团的名单,每天早上八点执行,查询报名结束时间为前一天的线路 + **/ +@IocBean(name = "staffTherapySendTakePartInUserByLineJob") +public class SendTakePartInUserByLineJob implements Job { + + @Inject + private TherapyEmail emailUtil; + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + + //获取昨天 + String yesterday = DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd"); + //先查询符合条件的线路 + List unionSelects = + enrollService.dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("Date(signUpEndTime)", "=", yesterday).and("enable", "=", true)); + List selectIdList = unionSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + Map selectMap = unionSelects.stream().collect(Collectors.toMap(TheRapyRecuperationLineUnionSelect::getId, o -> o)); + + //在查询这些线路的报名人员 + Sql sql = Sqls.create(""" + SELECT + e.*, + concat(l.lineName, ifnull(concat('【', ta.travelAgencyName, '】'), ''), ifnull(concat('-', su.unionname), '')) as lineName, + ta.id as travelId, + ta.travelAgencyName, + concat(s.playStartTime, '至' , s.playEndTime) as playTime, + (select count(1) from staff_therapy_enroll_companion ec where ec.trreId = e.id and ec.age >= 18) as companionCount, + (select GROUP_CONCAT(ec.userName, '(', ec.idcard, '、', ec.mobile, ')') from staff_therapy_enroll_companion ec where ec.trreId = e.id) as companionInfo, + u.schoolTime + FROM + staff_therapy_enroll e + LEFT JOIN `staff_therapy_user` u on e.loginName = u.loginname + LEFT JOIN staff_therapy_line_union_select s ON e.takePartInLineId = s.id + left join staff_therapy_line l on l.id = s.lineId + left join staff_therapy_travel_agency ta on ta.id = s.travelAgencyId + left join staff_therapy_union su on su.id = s.unionId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("takePartInLineId", "in", selectIdList); + cnd.and("isNormal", "=", true); + cnd.and("stateId", "=", TheRapyRecuperationState.PASS); + cnd.and("year(signingUptime)", "=", DateUtil.thisYear()); + cnd.asc("l.serialNumber").asc("s.playStartTime").asc("e.signingUptime"); + sql.setCondition(cnd); + List enrolls = enrollService.listMap(sql); + + if (Lang.isNotEmpty(enrolls)) { + enrolls.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + } + + //按照选择线路id分组,便于判断是否成团 + Map> enrollGroup = enrolls.stream().collect(Collectors.groupingBy(o -> o.getString("takePartInLineId"))); + + // 成团人数口径与统计页保持一致:报名教职工本人 + 18 岁及以上家属人数。 + List enrollList = enrollGroup.entrySet().stream() + .filter(entry -> selectMap.containsKey(entry.getKey()) && (entry.getValue().size() + entry.getValue().stream().mapToInt(o -> o.getInt("companionCount")).sum()) >= selectMap.get(entry.getKey()).getEstimatedFamilyNumbers()) + .flatMap(entry -> entry.getValue().stream()) + .collect(Collectors.toList()); + + //按旅行社分组 + Map> enrollsMap = enrollList.stream().collect(Collectors.groupingBy(o -> o.getString("travelId"))); + + List travelAgencyList = enrollService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW()); + for (TheRapyRecuperationTravelAgency item : travelAgencyList) { + String email = item.getEmail(); + if (StrUtil.isBlank(email)) continue; + List userList = enrollsMap.get(item.getId()); + if (Lang.isEmpty(userList)) continue; + List entityList = new ArrayList<>(); + entityList.add(new ExcelExportEntity("姓名", "userName", 20)); + entityList.add(new ExcelExportEntity("身份证号", "idCard", 20)); + entityList.add(new ExcelExportEntity("联系电话", "mobile", 20)); + entityList.add(new ExcelExportEntity("所属工会", "unionName", 20)); + entityList.add(new ExcelExportEntity("报名线路", "lineName", 50)); + entityList.add(new ExcelExportEntity("出行时间", "playTime", 50)); + ExcelExportEntity entity = new ExcelExportEntity("家属信息", "companionInfo", 50); + entity.setWrap(true); + entityList.add(entity); + entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 50)); + entityList.add(new ExcelExportEntity("备注", "remark", 30)); + + File xls = new File("C:/temp/" + item.getTravelAgencyName() + "疗休养线路出行人员名单.xls"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(xls); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, userList); + workbook.write(fileOutputStream); + fileOutputStream.close(); + emailUtil.send(email, item.getTravelAgencyName() + "疗休养线路出行人员名单", false, xls); + if (xls.exists()) { + xls.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByTravelJob.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByTravelJob.java new file mode 100644 index 0000000..e6fe71b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/job/SendTakePartInUserByTravelJob.java @@ -0,0 +1,113 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.job; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import org.apache.poi.ss.usermodel.Workbook; +import org.nutz.dao.Cnd; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @version 1.0 + * @Author zzr + * @name:SendTakePartInUserByTravelJob + * @Date 2024/5/27 10:05 + * @注释 + */ +@IocBean(name = "staffTherapySendTakePartInUserByTravelJob") +public class SendTakePartInUserByTravelJob implements Job { + + @Inject + private TherapyEmail emailUtil; + + @Inject + private TheRapyRecuperationEnrollService enrollService; + + @Override + public void execute(JobExecutionContext context) throws JobExecutionException { + Sql sql = Sqls.create(""" + SELECT + te.*, + travel.email, + travel.travelAgencyName, + u.schoolTime + FROM + `staff_therapy_enroll` te + LEFT JOIN `staff_therapy_user` u on te.loginName = u.loginname + LEFT JOIN `staff_therapy_travel_agency` travel ON travel.id = te.takePartInTravelAgencyId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("te.isNormal","=",1); + cnd.and("te.stateId","=",2750); + cnd.and("te.signingUptime",">=", DateUtil.format(DateUtil.yesterday(), "yyyy-MM-dd HH:mm:ss")); + cnd.and("te.signingUptime","<=", DateUtil.now()); + cnd.and("te.takePartInTravelAgencyId","is not",null); + cnd.and("te.takePartInTravelAgencyId","!=",""); + cnd.groupBy("te.loginName"); + sql.setCondition(cnd); + List nutMaps = enrollService.listMap(sql); + + if (Lang.isNotEmpty(nutMaps)) { + + nutMaps.forEach(item -> { + String remark = TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")); + item.put("remark", remark); + }); + + Map> enrollsMap = nutMaps.stream().collect(Collectors.groupingBy(v -> v.getString("takePartInTravelAgencyId"))); + + List travelAgencyList = enrollService.dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW()); + for (TheRapyRecuperationTravelAgency item : travelAgencyList) { + String email = item.getEmail(); + if (StrUtil.isBlank(email)) continue; + List userList = enrollsMap.get(item.getId()); + if (Lang.isEmpty(userList)) continue; + List entityList = new ArrayList<>(); + entityList.add(new ExcelExportEntity("姓名", "userName", 20)); + entityList.add(new ExcelExportEntity("身份证号", "idCard", 20)); + entityList.add(new ExcelExportEntity("联系电话", "mobile", 20)); + entityList.add(new ExcelExportEntity("所属工会", "unionName", 20)); + entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 50)); + entityList.add(new ExcelExportEntity("备注", "remark", 30)); + + File xls = new File("C:/temp/"+item.getTravelAgencyName()+"疗休养自由组团出行人员名单.xls"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(xls); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, userList); + workbook.write(fileOutputStream); + fileOutputStream.close(); + emailUtil.send(email, item.getTravelAgencyName() + "疗休养自由组团出行人员名单", false, xls); + if (xls.exists()) { + xls.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportExcelMode.java new file mode 100644 index 0000000..156e505 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportExcelMode.java @@ -0,0 +1,53 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +/** + * 疗休养线路新导入模板,字段与PC端线路管理新增页面保持一致。 + */ +@Data +public class TheRapyLineImportExcelMode { + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "排序号") + private Integer serialNumber; + + @Excel(name = "线路名称") + private String lineName; + + @Excel(name = "时间标段") + private String lotId; + + @Excel(name = "线路类型") + private String regionalNature; + + @Excel(name = "交通工具") + private String trafficTools; + + @Excel(name = "最少成团人数包括家属") + private Integer estimatedFamilyNumbers; + + @Excel(name = "预计费用(元/人次)") + private String estimatedCost; + + @Excel(name = "组织形式") + private String signUpMode; + + @Excel(name = "联系人") + private String lineContact; + + @Excel(name = "联系方式", width = 20) + private String lineContactPhone; + + @Excel(name = "线路内容") + private String content; + + @Excel(name = "是否启用") + private String isEnabled; + + @Excel(name = "移动端缩略图", width = 20) + private String files; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportImageMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportImageMode.java new file mode 100644 index 0000000..45c7afb --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyLineImportImageMode.java @@ -0,0 +1,30 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode; + +import lombok.Data; + +/** + * 线路导入模板内嵌图片数据,承载“移动端缩略图”列解析出的图片内容。 + */ +@Data +public class TheRapyLineImportImageMode { + + /** + * Excel数据行下标,从0开始,对应导入明细集合下标。 + */ + private Integer rowIndex; + + /** + * 导入图片原始文件名,用于写入sys_file.filename。 + */ + private String fileName; + + /** + * 图片扩展名,用于生成FTP文件名与校验图片类型。 + */ + private String extension; + + /** + * 图片二进制内容,后续在service层统一上传并保存文件记录。 + */ + private byte[] data; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyRecuperationEnrollExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyRecuperationEnrollExcelMode.java new file mode 100644 index 0000000..1939f2b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyRecuperationEnrollExcelMode.java @@ -0,0 +1,22 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +import java.util.Date; + +@Data +public class TheRapyRecuperationEnrollExcelMode { + + @Excel(name = "工号") + private String loginName; + + @Excel(name = "姓名") + private String userName; + + @Excel(name = "参加时间") + private Date takePartInTime; + + @Excel(name = "标段时间") + private String lotId; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java new file mode 100644 index 0000000..4d9a542 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelAgencyExcelMode.java @@ -0,0 +1,39 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode; + + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class TheRapyTravelAgencyExcelMode { + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "排序编号") + private String serialNumber; + + @Excel(name = "旅行社名称") + private String travelAgencyName; + + @Excel(name = "旅行社联系人") + private String contact; + + @Excel(name = "联系电话") + private String contactMobileNumber; + + @Excel(name = "邮箱") + private String email; + + @Excel(name = "最多承担人数") + private Integer maxUndertakeNumber; + + @Excel(name = "官网") + private String officialWebsite; + + @Excel(name = "备注") + private String note; + + @Excel(name = "是否启用(是/否)") + private String isDisabled; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelLineExcelMode.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelLineExcelMode.java new file mode 100644 index 0000000..48d160b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/mode/TheRapyTravelLineExcelMode.java @@ -0,0 +1,69 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import lombok.Data; + +@Data +public class TheRapyTravelLineExcelMode { + + @Excel(name = "年度") + private Integer year; + + @Excel(name = "排序编号") + private Integer serialNumber; + + @Excel(name = "线路名称") + private String lineName; + + @Excel(name = "旅行社名称") + private String travelAgencyId; + + @Excel(name = "活动范围") + private String regionalNature; + + @Excel(name = "最少参与教工") + private Integer minimumGroupSize; + +// @Excel(name = "创建模式(分工会/校工会)") +// private String createMode; +// +// @Excel(name = "报名模式(分工会/自由)") +// private String signUpMode; +// +// @Excel(name = "联系人") +// private String lineContact; +// +// @Excel(name = "联系方式") +// private String lineContactPhone; +// +// @Excel(name = "报名开始时间") +// private Date signUpStartTime; +// +// @Excel(name = "报名截止时间") +// private Date signUpEndTime; +// +// @Excel(name = "变更截止时间") +// private Date changeEndTime; +// +// @Excel(name = "出行开始时间") +// private Date playStartTime; +// +// @Excel(name = "出行结束时间") +// private Date playEndTime; + + @Excel(name = "时间标段") + private String lotId; + + @Excel(name = "预计费用") + private String estimatedCost; + +// @Excel(name = "交通工具") +// private String trafficTools; + + @Excel(name = "详细信息") + private String content; + + @Excel(name = "是否启用(是/否)") + private String isDisabled; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationBaseManagement.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationBaseManagement.java new file mode 100644 index 0000000..71bb429 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationBaseManagement.java @@ -0,0 +1,158 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.budwk.app.sys.models.Sys_file; +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationBaseManagement + * @Description: TODO + * @Author zzr + * @Date 2023/6/5 + * @Version V1.0 + **/ + +@Data +@Table("staff_therapy_base_management") +@Accessors(chain = true) +public class TheRapyRecuperationBaseManagement { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.INT) + @Comment("年度") + @Excel(name = "年度") + private Integer year; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("排序编号") + @Excel(name = "排序编号") + private String sortNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("基地名称") + @Excel(name = "目的地名称") + private String baseName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("旅行社Id") + @Excel(name = "所属旅行社") + private String travelAgencyId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("区域") + @Excel(name = "活动范围(省内/省外)") + private String regionalNature; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("标段Id") + @Excel(name = "时间标段") + private String lotId; + + @Column + @ColDefine(customType = "text") + @Comment("疗休养详情") + @Excel(name = "详细信息") + private String content; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否禁用") + @Excel(name = "是否启用(是/否)") + private Boolean isDisabled; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("哪个分工会创建的") + private String createUnionId; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名开始时间") + @Excel(name = "报名开始时间") + private Date signUpStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名截至时间") + @Excel(name = "报名截至时间") + private Date signUpEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("变更截至时间") + @Excel(name = "变更截至时间") + private Date changeEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("活动开始时间") + @Excel(name = "活动开始时间") + private Date activityStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("活动结束时间") + @Excel(name = "活动结束时间") + private Date activityEndTime; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("预计费用") + @Excel(name = "预计费用") + private String estimatedCost; + + @Column + @ColDefine(type = ColType.MYSQL_JSON) + @Comment("缩略图") + private List files; + + @Column + @ColDefine(type = ColType.INT) + @Comment("创建模式(1.校工会 2.分工会)") + @Excel(name = "组织形式(分工会/校工会)") + private int createMode; + + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("基地联系人") + @Excel(name = "目的地联系人") + private String baseContactPerson; + + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("基地联系人电话") + @Excel(name = "联系电话") + private String baseContactNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("操作人") + private String opBy; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("操作时间") + private String opAt; + + + @One(field = "travelAgencyId") + private TheRapyRecuperationTravelAgency travelAgency; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationCluster.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationCluster.java new file mode 100644 index 0000000..3bdfc44 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationCluster.java @@ -0,0 +1,40 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster + * @Description: TODO + * @Author zxc + * @Date 2022/6/17:09:30 + * @Version V1.0 + **/ +@Data +@Table("staff_therapy_cluster") +@Accessors(chain = true) +public class TheRapyRecuperationCluster { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("线路id") + private String lineId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("团名") + private String clusterName; + + @Many(field = "clusterId") + private List members; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationClusterMember.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationClusterMember.java new file mode 100644 index 0000000..0644bc8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationClusterMember.java @@ -0,0 +1,60 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationClusterMember + * @Description: TODO + * @Author zxc + * @Date 2022/6/17:09:30 + * @Version V1.0 + **/ +@Data +@Table("staff_therapy_cluster_member") +@Accessors(chain = true) +public class TheRapyRecuperationClusterMember { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("线路id") + private String lineId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("团Id") + private String clusterId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 20) + @Comment("工号") + private String loginName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 20) + @Comment("姓名") + private String userName; + + @Column + @ColDefine(type = ColType.CHAR, width = 1) + @Comment("性别") + private String sex; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("工会") + private String unionName; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否领队") + private Boolean isLeader; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationConfig.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationConfig.java new file mode 100644 index 0000000..24eba5c --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationConfig.java @@ -0,0 +1,164 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; +import org.nutz.lang.util.NutMap; + +import java.util.Date; +import java.util.List; + +@Data +@Table("staff_therapy_config") +@Accessors(chain = true) +public class TheRapyRecuperationConfig { + + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 30) + @Comment("配置名称") + private String configName; + + @Column + @ColDefine(type = ColType.INT, width = 32) + @Comment("参加人员范围") + private Integer activityGroupId; + + /** + * 报名开始时间,用于基础设置页面控制全局报名开放区间。 + */ + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名开始时间") + private Date signUpStartTime; + + /** + * 报名结束时间,用于基础设置页面控制全局报名截止区间。 + */ + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名结束时间") + private Date signUpEndTime; + + /** + * 选择线路开始时间,用于控制分工会/校工会选择线路开放区间。 + */ + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("选择线路开始时间") + private Date lineSelectStartTime; + + /** + * 选择线路结束时间,用于控制分工会/校工会选择线路截止区间。 + */ + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("选择线路结束时间") + private Date lineSelectEndTime; + + @Column + @ColDefine(type = ColType.INT) + @Comment("省外名额分配") + private Integer outsideQuota; + + @Column + @ColDefine(type = ColType.FLOAT, width = 3, precision = 2) + @Comment("省外名额分配比例") + private Double outsideQuotaProportion; + + @Column + @ColDefine(type = ColType.INT) + @Comment("省外几年去一次") + private Integer outsideNumber; + + @Column + @ColDefine(type = ColType.INT) + @Comment("每年旅行频率") + private Integer travelFrequency; + + @Column + @ColDefine(type = ColType.INT) + @Comment("组团人数") + private Integer groupNumber; + + @Column + @ColDefine(type = ColType.INT) + @Comment("不可取消修改天数") + private Integer modifyDays; + + @Column + @ColDefine(type = ColType.INT) + @Comment("可以修改几次") + private Integer modifyNumber; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("省内线路是否审核") + @Default(value = "0") + private Boolean isSnLine; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("省外线路是否审核") + @Default(value = "0") + private Boolean isSwLine; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("旅行社是否审核") + @Default(value = "0") + private Boolean travelAudit; + + @Column + @ColDefine(type = ColType.MYSQL_JSON) + @Comment("标段") + private List modifyBd; + + /** + * 分工会线路数量配置。 + * 每个元素保存一个分工会的最低线路选择要求: + * unionId 为分工会 ID,minProvinceOutNumber 为最少省外线路数量, + * minProvinceInNumber 为最少省内线路数量。 + */ + @Column + @ColDefine(type = ColType.MYSQL_JSON) + @Comment("分工会线路数量配置") + private List unionLineNumberConfigs; + + + @Many(field = "configId") + private List lots; + + @Column + @ColDefine(type = ColType.INT) + @Comment("全批次最多教职工报名人数") + private Integer allLineSignUpNumber; + + @Column + @ColDefine(customType = "longtext") + @Comment("疗休养服务须知") + private String notice; + + @Column + @ColDefine(type = ColType.INT) + @Comment("省内起始年份") + private Integer provinceStartYear; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("床位信息") + @Default(value = "0") + private Boolean bedInfo; + + @Column + @ColDefine(type = ColType.INT) + @Comment("家属信息") + @Default(value = "0") + private Integer familyInfo; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnroll.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnroll.java new file mode 100644 index 0000000..deec482 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnroll.java @@ -0,0 +1,207 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import cn.afterturn.easypoi.excel.annotation.Excel; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll + * @Description: 疗休养报名登记表 + * @Author zxc + * @Date 2022/5/31:16:58 + * @Version V1.0 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_enroll") +@Accessors(chain = true) +public class TheRapyRecuperationEnroll extends LegacyBaseModel { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("工号") + @Excel(name = "工号") + private String loginName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("姓名") + @Excel(name = "姓名") + private String userName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 1) + @Comment("性别") + private String sex; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("本人单位") + private String unitName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("本人分工会") + private String unionName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("本人单位") + private String selfUnitId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("本人分工会Id") + private String selfUnionId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("参加的分工会") + private String takePartInUnionId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("参加线路") + private String takePartInLineId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("参加旅行社") + private String takePartInTravelAgencyId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("参加酒店") + private String takePartInBaseManagementId; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名时间") + private Date signingUptime; + + @Column + @ColDefine(type = ColType.DATE) + @Comment("参加时间") + @Excel(name = "参加时间", format = "yyyy-MM-dd") + private Date takePartInTime; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否参加") + private boolean isTakePartIn; + + @Column + @ColDefine(type = ColType.INT) + @Comment("审核状态") + private Integer stateId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("本人分工会审核Id") + private String selfUnionAuditId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("床位信息id") + private String bedInfoId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("参加的线路分工会审核Id") + private String joinLineUnionAuditId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 18) + @Comment("身份证号") + private String idCard; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 20) + @Comment("手机号") + private String mobile; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否正常(true正常 false该报名记录已被管理员废弃)") + private boolean isNormal; + + /** + * 同伴信息 + */ + @Many(field = "trreId") + private List companionList; + + /** + * 酒店信息 + */ + @One(field = "takePartInBaseManagementId") + private TheRapyRecuperationBaseManagement managementInfo; + + /** + * 线路信息 + */ +// @One(field = "takePartInLineId") + private TheRapyRecuperationLine lineInfo; + + private String lineId; + + /** + * 床位信息 + */ + @One(field = "bedInfoId") + private TheRapyRecuperationEnrollBed bedInfo; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("对旅行社的评价(几星)") + private String evaluationForTravelAgency; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("对线路的评价(几星)") + private String evaluationForLine; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("对旅途的评价(几星)") + private String evaluationForJourney; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 100) + @Comment("反馈内容") + private String feedbackContent; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("标段时间") + private String lotId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("校工会审核Id") + private String schoolUnionAuditId; + + @Column + @ColDefine(type = ColType.INT) + @Comment("家属数量") + private Integer familyNumber; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否报销") + private Boolean isReimbursement; + + private String firstLetter; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollBed.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollBed.java new file mode 100644 index 0000000..e92612b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollBed.java @@ -0,0 +1,48 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollBed + * @Description: 报名拼床信息 + * @Author zxc + * @Date 2022/6/2:14:44 + * @Version V1.0 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_enroll_bed") +@Accessors(chain = true) +public class TheRapyRecuperationEnrollBed extends LegacyBaseModel { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("床型") + private String bedType; + + @Column + @ColDefine(type = ColType.INT) + @Comment("床位数") + private Integer bedNum; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("一起睡吗 搞基") + private boolean isSleepTogether; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("意向拼房人") + private String otherSleepUser; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollChangeRecord.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollChangeRecord.java new file mode 100644 index 0000000..fc03d2e --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollChangeRecord.java @@ -0,0 +1,37 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollChangeRecord + * @Description: 疗休养登记变更记录表 + * @Author zxc + * @Date 2022/5/31:17:10 + * @Version V1.0 + **/ +@Data +@Table("staff_therapy_enroll_change_record") +@Accessors(chain = true) +public class TheRapyRecuperationEnrollChangeRecord { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("变更记录id") + private String enrollId; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("变更时间") + private Date changeTime; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollCompanion.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollCompanion.java new file mode 100644 index 0000000..fb1d6b7 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationEnrollCompanion.java @@ -0,0 +1,79 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollFamily + * @Description: TODO + * @Author zxc + * @Date 2022/5/31:17:07 + * @Version V1.0 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_enroll_companion") +@Accessors(chain = true) +public class TheRapyRecuperationEnrollCompanion extends LegacyBaseModel { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("报名记录表Id") + private String trreId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("工号") + private String loginName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("姓名") + private String userName; + + @Column + @ColDefine(type = ColType.CHAR, width = 1) + @Comment("性别") + private String sex; + + @Column + @ColDefine(type = ColType.INT) + @Comment("年龄") + private Integer age; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("关系") + private String relation; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 18) + @Comment("身份证号") + private String idCard; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 18) + @Comment("手机号") + private String mobile; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("床位信息id") + private String bedInfoId; + + /** + * 床位信息 + */ + @One(field = "bedInfoId") + private TheRapyRecuperationEnrollBed bedInfo; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLine.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLine.java new file mode 100644 index 0000000..aa62b15 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLine.java @@ -0,0 +1,160 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import com.budwk.app.sys.models.Sys_file; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine + * @Description: 疗休养线路管理 + * @Author zxc + * @Date 2022/5/31:09:13 + * @Version V1.0 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_line") +@Accessors(chain = true) +public class TheRapyRecuperationLine extends LegacyBaseModel { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.INT) + @Comment("编号") + private Integer serialNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("线路名称") + private String lineName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("旅行社Id") + private String travelAgencyId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("区域性质") + private String regionalNature; + + @Column + @ColDefine(type = ColType.INT) + @Comment("游玩天数") + private Integer playNumberOfDays; + + @Column + @ColDefine(customType = "text") + @Comment("疗休养内容") + private String content; + + @Column + @ColDefine(type = ColType.INT) + @Comment("最少参与教工") + private Integer minimumGroupSize; + + @Column + @ColDefine(type = ColType.INT) + @Comment("年度") + private Integer year; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否禁用") + private boolean isDisabled; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("哪个分工会创建的") + private String createUnionId; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名开始时间") + private Date signUpStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名截至时间") + private Date signUpEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("变更截至时间") + private Date changeEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("游玩开始时间") + private Date playStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("游玩结束时间") + private Date playEndTime; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("交通工具") + private String trafficTools; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("预计费用") + private String estimatedCost; + + @Column + @ColDefine(type = ColType.INT) + @Comment("成团人数包括家属") + private Integer estimatedFamilyNumbers; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 30) + @Comment("缩略图") + private String files; + + @Column + @ColDefine(type = ColType.INT) + @Comment("报名模式(1.分工会 2.自由)") + private Integer signUpMode; + + @Column + @ColDefine(type = ColType.INT) + @Comment("创建模式(1.分工会 2.校工会)") + private int createMode; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("标段") + private String lotId; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("联系人") + private String lineContact; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("联系电话") + private String lineContactPhone; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否家属报名") + private Boolean isFamilySignUp; + + @One(field = "travelAgencyId") + private TheRapyRecuperationTravelAgency travelAgency; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLineUnionSelect.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLineUnionSelect.java new file mode 100644 index 0000000..a5b8971 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLineUnionSelect.java @@ -0,0 +1,158 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.Date; + + +/** + * 疗休养线工会选择 + * + * @author jug + * @date 2023/06/26 + */ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_line_union_select") +@Accessors(chain = true) +public class TheRapyRecuperationLineUnionSelect extends LegacyBaseModel { + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("分工会id") + private String unionId; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("线路id") + private String lineId; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("选择时间") + private Date selectTime; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("选择用户") + private String selectUserId; + + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名开始时间") + private Date signUpStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("报名截至时间") + private Date signUpEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("变更截至时间") + private Date changeEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("调剂报名截止时间") + private Date adjustSignUpEndTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("游玩开始时间") + private Date playStartTime; + + @Column + @ColDefine(type = ColType.DATETIME) + @Comment("游玩结束时间") + private Date playEndTime; + + /** + * 线路信息 + */ + @One(field = "lineId") + private TheRapyRecuperationLine lineInfo; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("联系人") + private String contact; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("联系电话") + private String contactPhone; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("负责人") + private String principal; + + @Column + @ColDefine(type = ColType.VARCHAR) + @Comment("联系方式") + private String principalContact; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否公开") + private Boolean isOpen; + + @Column + @ColDefine(type = ColType.INT) + @Comment("最少参与教工") + private Integer minimumGroupSize; + + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("交通工具") + private String trafficTools; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("预计费用") + private String estimatedCost; + + @Column + @ColDefine(type = ColType.INT) + @Comment("成团人数包括家属") + private Integer estimatedFamilyNumbers; + + @Column + @ColDefine(type = ColType.INT) + @Comment("最多人数") + private Integer maxPeopleNumber; + + @Column + @ColDefine(type = ColType.INT) + @Comment("报名模式、组织形式(1.分工会 2.校工会)") + private Integer signUpMode; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否启用") + private Boolean enable; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("旅行社id") + private String travelAgencyId; + + /** + * 页面提交的选择线路模式,仅用于接收请求参数,不持久化到数据库。 + * 1 表示分工会选择线路,2 表示校工会选择线路。 + */ + private Integer mode; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLot.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLot.java new file mode 100644 index 0000000..6ae29d8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationLot.java @@ -0,0 +1,47 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import lombok.Data; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot + * @Description: TODO + * @Author zzr + * @Date 2023/6/6 + * @Version V1.0 + **/ + +@Table("staff_therapy_lot") +@Data +@Accessors(chain = true) +public class TheRapyRecuperationLot { + + @Name + @Comment("id") + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("标段") + private String lotName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("标段值") + private String lotValue; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 10) + @Comment("费用") + private Integer activityCost; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @Comment("配置ID") + private String configId; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationTravelAgency.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationTravelAgency.java new file mode 100644 index 0000000..3b432f9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/TheRapyRecuperationTravelAgency.java @@ -0,0 +1,94 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.LegacyBaseModel; +import com.budwk.app.sys.models.Sys_file; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency + * @Description: 疗休养旅行社管理 + * @Author zxc + * @Date 2022/5/31:14:39 + * @Version V1.0 + **/ +@EqualsAndHashCode(callSuper = true) +@Data +@Table("staff_therapy_travel_agency") +@Accessors(chain = true) +public class TheRapyRecuperationTravelAgency extends LegacyBaseModel { + + + @Name + @Comment("id") + @PrevInsert(uu32 = true) + private String id; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("旅行社编号") + private String serialNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("旅行社名称") + private String travelAgencyName; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 20) + @Comment("旅行社联系人") + private String contact; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 11) + @Comment("旅行社联系人手机") + private String contactMobileNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 50) + @Comment("旅行社邮箱") + private String email; + + /** + * 旅行社最多承担出行人数,移动端线路报名时按该旅行社承担的所有线路合并校验。 + */ + @Column + @ColDefine(type = ColType.INT) + @Comment("最多承担人数") + private Integer maxUndertakeNumber; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 100) + @Comment("旅行社官网") + private String officialWebsite; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 100) + @Comment("备注") + private String note; + + @Column + @ColDefine(type = ColType.INT) + @Comment("年度") + private Integer year; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否禁用") + private boolean isDisabled; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 100) + @Comment("缩略图") + private String files; + + @Column + @ColDefine(type = ColType.BOOLEAN) + @Comment("是否自由组团") + private Boolean signUpTravelAgency; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewTimeSlotVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewTimeSlotVo.java new file mode 100644 index 0000000..1824694 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewTimeSlotVo.java @@ -0,0 +1,105 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +import java.util.Date; + +/** + * 管理员查看分工会已选择线路的出行时间段。 + */ +@Data +@Accessors(chain = true) +public class LineSelectionOverviewTimeSlotVo { + + /** + * 分工会选择线路记录 ID。 + */ + private String id; + + /** + * 报名开始时间。 + */ + private Date signUpStartTime; + + /** + * 报名结束时间。 + */ + private Date signUpEndTime; + + /** + * 变更截止时间。 + */ + private Date changeEndTime; + + /** + * 调剂报名截止时间。 + */ + private Date adjustSignUpEndTime; + + /** + * 出行开始时间。 + */ + private Date playStartTime; + + /** + * 出行结束时间。 + */ + private Date playEndTime; + + /** + * 旅行社名称。 + */ + private String travelAgencyName; + + /** + * 旅行社 ID。 + */ + private String travelAgencyId; + + /** + * 联系人。 + */ + private String contact; + + /** + * 联系电话。 + */ + private String contactPhone; + + /** + * 联络人。 + */ + private String principal; + + /** + * 联络人联系方式。 + */ + private String principalContact; + + /** + * 交通工具。 + */ + private String trafficTools; + + /** + * 预计费用。 + */ + private String estimatedCost; + + /** + * 最少成团人数,包含家属。 + */ + private Integer estimatedFamilyNumbers; + + /** + * 最多人数,为 0 时不限制。 + */ + private Integer maxPeopleNumber; + + /** + * 是否启用。 + */ + private Boolean enable; + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewVo.java new file mode 100644 index 0000000..7bdf245 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/LineSelectionOverviewVo.java @@ -0,0 +1,87 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 管理员查看分工会已选择线路列表。 + */ +@Data +@Accessors(chain = true) +public class LineSelectionOverviewVo { + + /** + * 线路 ID,对应 staff_therapy_line.id。 + */ + private String lineId; + + /** + * 分工会选择线路记录 ID,用于定位该线路已选择状态。 + */ + private String lineUnionSelectId; + + /** + * 当前列表行对应的分工会选择线路记录 ID,保留该字段用于兼容前端提交参数。 + */ + private String lineUnionSelectIds; + + /** + * 年度。 + */ + private Integer year; + + /** + * 线路序号。 + */ + private Integer serialNumber; + + /** + * 线路名称。 + */ + private String lineName; + + /** + * 线路类型,例如省内、省外。 + */ + private String regionalNature; + + /** + * 时间标段名称。 + */ + private String lotName; + + /** + * 出行时间段,多个时间段用逗号连接。 + */ + private String playTimes; + + /** + * 报名时间段,多个时间段用逗号连接。 + */ + private String signUpTimes; + + /** + * 调剂报名截止时间。 + */ + private String adjustSignUpEndTime; + + /** + * 组织形式,1 表示分工会,2 表示校工会。 + */ + private Integer signUpMode; + + /** + * 选择线路的分工会 ID。 + */ + private String unionId; + + /** + * 选择线路的分工会名称。 + */ + private String unionName; + + /** + * 是否开放对外报名。 + */ + private Boolean isOpen; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/TravelAgencyMonthlyEnrollStatisticsVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/TravelAgencyMonthlyEnrollStatisticsVo.java new file mode 100644 index 0000000..77cb6ed --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/TravelAgencyMonthlyEnrollStatisticsVo.java @@ -0,0 +1,42 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 旅行社月度报名数量统计。 + */ +@Data +@Accessors(chain = true) +public class TravelAgencyMonthlyEnrollStatisticsVo { + + /** + * 旅行社 ID,对应 staff_therapy_travel_agency.id。 + */ + private String travelAgencyId; + + /** + * 旅行社名称,用于图表分组展示。 + */ + private String travelAgencyName; + + /** + * 统计年度。 + */ + private Integer year; + + /** + * 月份数字,取值范围 1-12。 + */ + private Integer month; + + /** + * 月份展示名称,例如 1月、2月。 + */ + private String monthName; + + /** + * 当前旅行社在该月份的有效报名数量。 + */ + private Integer enrollNumber; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionEnrollStatisticsVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionEnrollStatisticsVo.java new file mode 100644 index 0000000..35d1cf1 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionEnrollStatisticsVo.java @@ -0,0 +1,42 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 二级工会疗休养出行人数统计。 + */ +@Data +@Accessors(chain = true) +public class UnionEnrollStatisticsVo { + + /** + * 二级工会 ID,对应报名人的本人分工会 selfUnionId。 + */ + private String unionId; + + /** + * 二级工会名称,用于图表横轴展示。 + */ + private String unionName; + + /** + * 统计年度。 + */ + private Integer year; + + /** + * 月份数字,取值范围 1-12。 + */ + private Integer month; + + /** + * 月份展示名称,例如 1月、2月。 + */ + private String monthName; + + /** + * 当前二级工会在该月份的有效报名人数。 + */ + private Integer enrollNumber; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineNumberStatisticsVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineNumberStatisticsVo.java new file mode 100644 index 0000000..138796e --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineNumberStatisticsVo.java @@ -0,0 +1,47 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 分工会线路数量配置与当前年度选择数量统计。 + */ +@Data +@Accessors(chain = true) +public class UnionLineNumberStatisticsVo { + + /** + * 分工会 ID,对应 sys_union.id。 + */ + private String unionId; + + /** + * 分工会名称,对应 sys_union.unionname。 + */ + private String unionName; + + /** + * 基础设置中配置的最低省外线路数量。 + */ + private Integer provinceOutNumber; + + /** + * 基础设置中配置的最低省内线路数量。 + */ + private Integer provinceInNumber; + + /** + * 当前年度该分工会已选择的省外线路数量。 + */ + private Integer selectedProvinceOutNumber; + + /** + * 当前年度该分工会已选择的省内线路数量。 + */ + private Integer selectedProvinceInNumber; + + /** + * 是否同时满足省外、省内最低选择数量要求。 + */ + private Boolean finished; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineSelectLimitVo.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineSelectLimitVo.java new file mode 100644 index 0000000..61c05e9 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/model/vo/UnionLineSelectLimitVo.java @@ -0,0 +1,32 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 分工会选择线路数量提示信息。 + */ +@Data +@Accessors(chain = true) +public class UnionLineSelectLimitVo { + + /** + * 当前登录人所属分工会在基础设置中配置的最少省外线路选择数量。 + */ + private Integer minProvinceOutNumber; + + /** + * 当前登录人所属分工会在基础设置中配置的最少省内线路选择数量。 + */ + private Integer minProvinceInNumber; + + /** + * 当前登录人所属分工会本年度已选择的省外线路数量。 + */ + private Integer selectedProvinceOutNumber; + + /** + * 当前登录人所属分工会本年度已选择的省内线路数量。 + */ + private Integer selectedProvinceInNumber; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationAuditService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationAuditService.java new file mode 100644 index 0000000..311622b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationAuditService.java @@ -0,0 +1,40 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +public interface TheRapyRecuperationAuditService extends TherapyService { + + + /** + * 根据分工会查询线路 + * + * @param + * @param unionId + * @param regionalNature 是否省内省外 可为空 + * @param year 可为空 + * @return + */ + List getXlByUnion(Integer state, String unionId, String regionalNature, String year,String endYear, Integer signUpMode, String agencyId); + + + /** + * + * @param id + * @return + */ + NutMap findOne(String id); + + + /** + * 校工会审核 + * @param stateId + * @param loginName + * @param adjustment + * @param takePartInLineId + */ + void schoolAudit(Integer stateId, String loginName,Boolean adjustment, String takePartInLineId); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationCommonService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationCommonService.java new file mode 100644 index 0000000..c7fdd22 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationCommonService.java @@ -0,0 +1,17 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType; + +public interface TheRapyRecuperationCommonService extends TherapyService { + + + /** + * 可以报名吗 + * + * @param loginName 用户名 + * @return boolean + */ + boolean canSignUp(String loginName, TheRapyRecuperationType theRapyRecuperationType); + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollJoinUserImportService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollJoinUserImportService.java new file mode 100644 index 0000000..1c24b15 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollJoinUserImportService.java @@ -0,0 +1,15 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; + +public interface TheRapyRecuperationEnrollJoinUserImportService extends TherapyService { + + List selectLineAndTravelAgencyList(Integer year, String keyword); + + Map> selectLineOrTravelAgency(Integer year); + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollService.java new file mode 100644 index 0000000..5e054bc --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationEnrollService.java @@ -0,0 +1,229 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.TravelAgencyMonthlyEnrollStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionEnrollStatisticsVo; +import org.nutz.dao.Cnd; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; + +/** + * 疗休养报名service + * + * @author jug + * @date 2022/06/01 + */ +public interface TheRapyRecuperationEnrollService extends TherapyService { + + + /** + * 报名页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param unionId 工会 ID + * @param trrt 疗休养线路类型 + * @param lineUnionType 线路筛选类型,1 本分工会、2 其他分工会、3 校工会、4 全部 + * @param lineKeyword 移动端线路名称搜索关键字 + * @param signUpStatus 报名状态筛选,0 全部、1 报名中、2 报名已结束 + * @return {@link Pagination} + */ + Pagination enrollPageData(PageForm pageForm, Integer year, String unionId, int trrt, Integer lineUnionType, String lineKeyword, Integer signUpStatus); + + List getSelectLineById(String lineId, String usId, String unionId, int trrt, Integer lineUnionType, Integer signUpStatus); + + Object openSignUser(String usId, String travelId, String searchKeyWord); + + /** + * 线路报名 + * + * @param enrollInfo 登记信息 + */ + void doSignUpForLine(TheRapyRecuperationEnroll enrollInfo); + + /** + * 校工会代选线路报名。 + * + * @param enrollInfo 包含被报名人工号和线路选择表id的报名信息 + */ + void doProxySignUpForLine(TheRapyRecuperationEnroll enrollInfo); + + + /** + * 变更报名 + * + * @param enrollInfo 登记信息 + */ + void updateSignUpLine(TheRapyRecuperationEnroll enrollInfo); + + /** + * 报名旅行社 + * + * @param enrollInfo 登记信息 + */ + void doSignUpForTravelAgency(TheRapyRecuperationEnroll enrollInfo); + + /** + * 报名酒店 + * + * @param enrollInfo 登记信息 + */ + void doSignUpForHotel(TheRapyRecuperationEnroll enrollInfo); + + void updateSignUpHotel(TheRapyRecuperationEnroll enrollInfo); + + /** + * 变更报名旅行社 + * + * @param enrollInfo 登记信息 + */ + void updateSignUpTravelAgency(TheRapyRecuperationEnroll enrollInfo); + + /** + * 验证报名登记信息 + * + * @param enrollInfo 登记信息 + * @param loginName 用户名 + * @return {@link Map}<{@link Boolean}, {@link String}> + */ + Map validSignUpInfo(String loginName, TheRapyRecuperationEnroll enrollInfo); + + Map validSignUpInfoForZJXU(String loginName, TheRapyRecuperationEnroll enrollInfo); + + Map validSignUpInfoForZJNU(String loginName, TheRapyRecuperationEnroll enrollInfo); + + /** + * 校工会代选线路报名校验,不校验旅行社最多承担人数。 + * + * @param loginName 被报名人工号 + * @param enrollInfo 报名信息 + * @return {@link Map}<{@link Boolean}, {@link String}> + */ + Map validProxySignUpInfoForLine(String loginName, TheRapyRecuperationEnroll enrollInfo); + + /** + * 校工会代选线路人员搜索。 + * + * @param keyword 姓名或工号关键字 + * @return 人员下拉列表 + */ + List searchProxySignUpUsers(String keyword); + + /** + * 校工会代选线路查询,返回校工会和分工会已选择的线路时间段。 + * + * @param year 主页面选择年份 + * @return 线路时间段下拉列表 + */ + List getProxySignUpLines(Integer year); + + /** + * 补发指定年度已标记删除的未成团通知。 + * + * @param year 报名年度,按 signingUptime 所在年份筛选 + * @return 实际触发消息发送的报名记录数量 + */ + int resendDeletedFailNotice(Integer year); + + /** + * 手动发送所选线路的成团邮件给旅行社。 + * + * @param lineUnionSelectIds 统计页勾选的线路选择记录 ID,对应 staff_therapy_line_union_select.id + * @return 实际发送邮件的旅行社数量 + */ + int sendTakePartInUserByLineMail(List lineUnionSelectIds); + + /** + * 校验线路指定旅行社最多承担人数。 + * + * @param enrollInfo 报名信息 + * @return {@link Map}<{@link Boolean}, {@link String}> + */ + Map validTravelAgencyMaxUndertakeNumber(TheRapyRecuperationEnroll enrollInfo); + + /** + * 我报名的页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + Pagination mySignUpPageData(PageForm pageForm, Cnd cnd, int trrt, Integer year); + + + /** + * 找到报名信息通过id + * + * @param id id + * @return {@link TheRapyRecuperationEnroll} + */ + TheRapyRecuperationEnroll findSignUpInfoById(String id); + + + /** + * 删除我的报名信息 + * + * @param id id + */ + void deleteMyEnrollInfoById(String id); + + /** + * 校验我的疗休养报名是否允许取消。 + * + * @param id 报名记录id + * @return 为空表示允许取消;非空表示不允许取消的提示文案 + */ + String validateCanDeleteMyEnrollInfo(String id); + + + /** + * 手机端线路介绍所有信息 + * + * @param usId usId + * @param usUnionId usUnionId + * @return {@link NutMap} + */ + NutMap selectLineAllInfo(String usId, String usUnionId, String year); + + List getTheRapyUnions(Integer year, int theRapyRecuperationType); + + /** + * 按旅行社统计指定年度每个月的有效报名数量。 + * + * @param year 统计年度,为空时使用当前年度 + * @return 旅行社月度报名数量 VO 列表,只返回有报名数据的月份 + */ + List getTravelAgencyMonthlyEnrollStatistics(Integer year); + + /** + * 构建旅行社月度统计导出数据。 + * 参数 year 为统计年度;返回 NutMap,其中 months 为有数据的月份数字列表,rows 为按旅行社横向展开后的导出行。 + * + * @param year 统计年度,为空时使用当前年度 + * @return 导出数据,包含动态月份列和行数据 + */ + NutMap getTravelAgencyMonthlyEnrollExportData(Integer year); + + /** + * 按报名人本人二级工会和报名月份统计指定年度有效报名人数。 + * + * @param year 统计年度,为空时使用当前年度 + * @return 二级工会月度出行人数 VO 列表,只返回有报名数据的月份 + */ + List getUnionEnrollStatistics(Integer year); + + /** + * 构建二级工会月度出行人数导出数据。 + * 参数 year 为统计年度;返回 NutMap,其中 months 为有数据的月份数字列表,rows 为按二级工会横向展开后的导出行。 + * + * @param year 统计年度,为空时使用当前年度 + * @return 导出数据,包含动态月份列和行数据 + */ + NutMap getUnionEnrollExportData(Integer year); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineAdjustmentService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineAdjustmentService.java new file mode 100644 index 0000000..27522b7 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineAdjustmentService.java @@ -0,0 +1,16 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; + +import java.util.List; + +public interface TheRapyRecuperationLineAdjustmentService extends TherapyService { + + + Pagination pageData(PageForm pageForm, Integer year, String lineId, String unionId, String keywords, String regionalNature, String lotId); + + List findUnionSignUpModeUserList(String lineId, String unionId); + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineClusterService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineClusterService.java new file mode 100644 index 0000000..e8e96cd --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineClusterService.java @@ -0,0 +1,40 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster; + +import java.util.List; + +public interface TheRapyRecuperationLineClusterService extends TherapyService { + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param unionId 工会id + * @param keywords 关键字 + * @return {@link Pagination} + */ + Pagination pageData(PageForm pageForm, Integer year, String unionId, String keywords); + + /** + * 查询组团信息 + * + * @param lineId 线路id + * @param lineId 归属工会id + * @return {@link Object} + */ + Object findClusterInfo(String lineId, String usUnionId); + + /** + * 设置组团成员 + * + * @param clusters 集群 + * @param lineId 行id + */ + void setClusterMembers(List clusters, String lineId); + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineService.java new file mode 100644 index 0000000..b63c7bf --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineService.java @@ -0,0 +1,107 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportImageMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import org.nutz.dao.Cnd; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService + * @Description: 疗休养线路管理service + * @Author zxc + * @Date 2022/5/31:09:45 + * @Version V1.0 + **/ +public interface TheRapyRecuperationLineService extends TherapyService { + + + /** + * 删除线路 + * + * @param lineId 线路id + */ + void deleteLine(String lineId); + + + /** + * 添加线路 + * + * @param line 线路 + */ + void addLine(TheRapyRecuperationLine line); + + /** + * 编辑线路 + * + * @param line 线路 + */ + void editLine(TheRapyRecuperationLine line); + + + /** + * 开启或关闭线路 + * + * @param lineId 线路id + */ + void openClosedLine(String lineId); + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + Pagination pageData(PageForm pageForm, Cnd cnd); + + + /** + * 查询线路详细信息 + * + * @param lineId 行id + * @return {@link TheRapyRecuperationLine} + */ + TheRapyRecuperationLine selectLineInfoById(String lineId); + + + /** + * 根据分工会选择的线路id查询所该线路报名的人 + * + * @param pageForm 页面形式 + * @param lineId 行id + * @return {@link List}<{@link NutMap}> + */ + Pagination selectLineUser(PageForm pageForm, String lineId, String unionId); + + + /** + * 清除线路详细信息 + * + * @param lineId 线路id + */ + void deleteLineInfoCache(String lineId); + + /** + * 查看各个分工会设置的时间信息 + * + * @param lineId 线路id + * @return {@link List}<{@link NutMap}> + */ + List viewUnionSelectTimeInfo(String lineId); + + /** + * 按PC端线路管理页面字段导入线路。 + * + * @param excelList 线路导入模板数据 + * @param imageMap 移动端缩略图列的内嵌图片,key为导入数据行下标 + * @return 导入成功数量 + */ + int importLineByPageFields(List excelList, Map imageMap); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineUnionSelectService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineUnionSelectService.java new file mode 100644 index 0000000..3a1bb30 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationLineUnionSelectService.java @@ -0,0 +1,108 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import org.nutz.dao.Cnd; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +/** + * 分工会选择线路 + * + * @author jug + * @date 2022/06/01 + */ +public interface TheRapyRecuperationLineUnionSelectService extends TherapyService { + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @param year 年度 + * @param mode 页面模式,1 表示分工会选择线路,2 表示校工会选择线路 + * @return {@link Pagination} + */ + Pagination pageData(PageForm pageForm, Cnd cnd, Integer year, Integer mode); + + + /** + * 选择线路 + * + * @param us 分工会选择线路信息 + */ + void selectLine(TheRapyRecuperationLineUnionSelect us); + + /** + * 保存分工会或校工会选择线路的出行时段。 + * + * @param lineUnionSelects 出行时段列表,mode 用于区分分工会和校工会页面 + */ + void selectLineTimes(TheRapyRecuperationLineUnionSelect[] lineUnionSelects); + + /** + * 管理员维护指定分工会已选择线路的全部出行时间段信息。 + * + * @param lineUnionSelects 出行时间段列表,每项包含时间、旅行社、联系人、人数和启用状态等字段 + * @param lineId 线路 ID,用于限定只能修改当前线路的时间段 + * @param unionId 分工会 ID,用于限定只能修改当前分工会选择的时间段 + * @param year 年度,用于限定当前页面筛选年度下的选择记录 + */ + void adminSaveLineTimes(TheRapyRecuperationLineUnionSelect[] lineUnionSelects, String lineId, String unionId, Integer year); + + + /** + * 已经选择的线路ids + * + * @param year 选择年份 + * @param mode 页面模式,1 表示分工会选择线路,2 表示校工会选择线路 + * @return {@link List}<{@link String}> + */ + List getHasSelectLineIds(Integer year, Integer mode); + + + /** + * 设置的活动时间信息 + * + * @param lineId 行id + * @return {@link Object} + */ + Object selectLineInfo(String lineId, String unionId,Integer mode, Integer year); + + /** + * 设置线路时间信息 + * + * @param unionSelect 联盟选择 + */ + void setLineInfo(TheRapyRecuperationLineUnionSelect unionSelect); + + + /** + * 查询某个分工会设置的线路时间信息 + * + * @param lineId 行id + * @param usUnionId 我们工会id + * @return {@link NutMap} + */ + TheRapyRecuperationLineUnionSelect findUsLineInfo(String lineId, String usUnionId); + + + /** + * 分工会取消选择线路 + * + * @param usId union_select 主键id + */ + void deSelect(String usId); + + /** + * 校验当前页面模式是否允许选择、修改或取消选择线路。 + * mode=2 表示校工会选择线路,不受基础设置选择线路时间控制; + * 其他模式在基础设置已配置完整开始/结束时间时,当前时间必须落在配置范围内。 + * + * @param mode 选择线路页面类型,1 表示分工会选择线路,2 表示校工会选择线路 + */ + void validateLineSelectTime(Integer mode); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationTravelAgencyService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationTravelAgencyService.java new file mode 100644 index 0000000..8260ebe --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/TheRapyRecuperationTravelAgencyService.java @@ -0,0 +1,79 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import org.nutz.dao.Cnd; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +/** + * 疗休养旅行社 + * + * @author jug + * @date 2022/05/31 + */ +public interface TheRapyRecuperationTravelAgencyService extends TherapyService { + + /** + * 删除旅行社 + * + * @param travelAgencyId 旅行社 ID + */ + void deleteTravelAgency(String travelAgencyId); + + + /** + * 添加旅行社 + * + * @param travelAgency 旅行社 + */ + void addTravelAgency(TheRapyRecuperationTravelAgency travelAgency); + + /** + * 编辑旅行社 + * + * @param travelAgency 旅行社 + */ + void editTravelAgency(TheRapyRecuperationTravelAgency travelAgency); + + + /** + * 开启或关闭旅行社 + * + * @param travelAgencyId 旅行社id + */ + void openTravelAgency(String travelAgencyId); + + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + Pagination pageData(PageForm pageForm, Cnd cnd); + + + /** + * 查询旅行社 + * + * @param cnd cnd + * @return {@link List}<{@link TheRapyRecuperationTravelAgency}> + */ + List selectAllTravelAgencyByYear(Cnd cnd); + + + /** + * 根据旅行社id查询所该旅行社报名的人,只查报旅行社的人跟线路没关系 + * + * @param pageForm 页面形式 + * @param id 旅行社id + * @return {@link List}<{@link NutMap}> + */ + Pagination selectAgencyUser(PageForm pageForm,String id); + +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/baseManage/TheRapyRecuperationBaseManagerService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/baseManage/TheRapyRecuperationBaseManagerService.java new file mode 100644 index 0000000..74e6189 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/baseManage/TheRapyRecuperationBaseManagerService.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.baseManage; + +import org.nutz.lang.util.NutMap; + +/** + * @Author JyuHsin + * @Date 2023/6/7 + * @Description + */ +public interface TheRapyRecuperationBaseManagerService { + + NutMap selectBaseAllInfo(String id); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationAuditServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationAuditServiceImpl.java new file mode 100644 index 0000000..af0f8b2 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationAuditServiceImpl.java @@ -0,0 +1,169 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyAudit; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollBed; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollCompanion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationAuditService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; + +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationAuditServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationAuditService { + public TheRapyRecuperationAuditServiceImpl(Dao dao) { + super(dao); + } + + @Inject + private TherapyMessage msgApi; + + @Override + public List getXlByUnion(Integer state, String unionId, String regionalNature, String year,String endYear, Integer signUpMode, String agencyId) { + + Sql sql = Sqls.create(""" + SELECT + line.*, + lineu.id as selectId, + un.unionname, + DATE_FORMAT(lineu.playStartTime,'%Y-%m-%d') as playStartTime1 + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_union un ON un.id = enroll.takePartInUnionId + $condition + """); + Cnd cnd = Cnd.NEW(); + if (Strings.isNotBlank(unionId)) { + cnd.and(Cnd.exps("enroll.takePartInUnionId", "=", unionId).or("enroll.selfUnionId", "=", unionId)); + } + if (state != null && (state == 3 || state == 1)) { + cnd.and("enroll.takePartInUnionId", "=", TherapyContext.getUnionId()); + } + if (state != null && state == 2) { + cnd.and("enroll.selfUnionId", "=", TherapyContext.getUnionId()); + cnd.and("enroll.takePartInUnionId", "!=", TherapyContext.getUnionId()); + } + cnd.andEX("lineu.signUpMode", "=", signUpMode); + cnd.andEX("line.regionalNature", "=", regionalNature); + addLineTravelAgencyCondition(cnd, agencyId); + if (StrUtil.isNotBlank(endYear)){ + cnd.andEX("YEAR(enroll.signingUptime)", ">=", year); + cnd.andEX("YEAR(enroll.signingUptime)", "<=", endYear); + } else { + cnd.andEX("YEAR(enroll.signingUptime)", "=", year); + } + cnd.and("enroll.takePartInLineId", "is not", null); + cnd.and("enroll.takePartInLineId", "!=", ""); + cnd.and("enroll.stateId", "=", TheRapyRecuperationState.PASS); + cnd.groupBy("line.id"); + cnd.having(Cnd.where("playStartTime1", "is not", null)); + cnd.asc("un.unionname").asc("lineu.lineId").asc("lineu.playStartTime"); + sql.setCondition(cnd); + return listMap(sql); + } + + /** + * 线路下拉按旅行社过滤。 + * 线路选择记录和线路主表都可能保存旅行社,因此同时匹配两处字段。 + * + * @param cnd 当前线路下拉查询条件 + * @param travelAgencyId 旅行社 ID,为空时不增加过滤条件 + */ + private void addLineTravelAgencyCondition(Cnd cnd, String travelAgencyId) { + if (StrUtil.isBlank(travelAgencyId)) { + return; + } + SqlExpressionGroup travelAgencyGroup = new SqlExpressionGroup(); + travelAgencyGroup.or("lineu.travelAgencyId", "=", travelAgencyId); + travelAgencyGroup.or("line.travelAgencyId", "=", travelAgencyId); + cnd.and(travelAgencyGroup); + } + + @Override + public NutMap findOne(String id) { + Sql sql = Sqls.create(""" + SELECT + lxs.travelAgencyName, + ta.travelAgencyName as joinTravelAgencyName, + enroll.*, + line.lineName, + if(enroll.takePartInUnionId!=enroll.selfUnionId,true,false) isTransferIn, + (SELECT COUNT(1) FROM staff_therapy_enroll_companion WHERE trreId=enroll.id and relation='亲属') isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_travel_agency lxs ON lxs.id = lineu.travelAgencyId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = enroll.takePartInTravelAgencyId + where enroll.id=@id + """).setParam("id", id); + + NutMap fetch = fetch(sql); + NutMap map = NutMap.NEW(); + if (fetch == null) { + return map.addv("viewData", NutMap.NEW()); + } + if (Strings.isNotBlank(fetch.getString("selfUnionAuditId"))) { + TherapyAudit selfUnionAudit = dao().fetch(TherapyAudit.class, fetch.getString("selfUnionAuditId")); + fetch.setv("selfUnionAudit", selfUnionAudit); + } + if (Strings.isNotBlank(fetch.getString("joinLineUnionAuditId"))) { + TherapyAudit joinLineUnionAudit = dao().fetch(TherapyAudit.class, fetch.getString("joinLineUnionAuditId")); + fetch.setv("joinLineUnionAudit", joinLineUnionAudit); + } + if (Strings.isNotBlank(fetch.getString("schoolUnionAuditId"))) { + TherapyAudit schoolUnionAudit = dao().fetch(TherapyAudit.class, fetch.getString("schoolUnionAuditId")); + fetch.setv("schoolUnionAudit", schoolUnionAudit); + } + if (Strings.isNotBlank(fetch.getString("bedInfoId"))) { + TheRapyRecuperationEnrollBed bedInfo = dao().fetch(TheRapyRecuperationEnrollBed.class, fetch.getString("bedInfoId")); + fetch.setv("bedInfo", bedInfo); + } + List companionList = dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "=", id)); + companionList.forEach(v -> { + if (Strings.isNotBlank(v.getBedInfoId())) { + v.setBedInfo(dao().fetch(TheRapyRecuperationEnrollBed.class, v.getBedInfoId())); + } + }); + map.addv("viewData", fetch.setv("companionList", companionList)); + + + return map; + } + + + @Override + public void schoolAudit(Integer stateId, String loginName, Boolean adjustment, String takePartInLineId) { + TherapyUser user = dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName)); + TheRapyRecuperationLineUnionSelect unionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", takePartInLineId)); + TheRapyRecuperationLine theRapyRecuperationLine = dao().fetch(TheRapyRecuperationLine.class, Cnd.where("id", "=", unionSelect.getLineId())); + + String content = "【智慧工会】%s老师您好,您报名的%s线路因报名人数不足已取消,请尽快进入智慧工会重新选择线路。" + .formatted(user.getUsername(),theRapyRecuperationLine.getLineName()); + + List list = List.of(Map.of("type", "User", "userId", user.getLoginname(), "name", user.getUsername())); + if (stateId.equals(TheRapyRecuperationState.PASS)) { + content = "【智慧工会】%s老师您好,您报名的%s线路已组团成功,请按约定出行。" + .formatted(user.getUsername(), theRapyRecuperationLine.getLineName()); + } + //msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", MsgApi.sendMode.normal.name()); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationCommonServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationCommonServiceImpl.java new file mode 100644 index 0000000..9304ba3 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationCommonServiceImpl.java @@ -0,0 +1,66 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.hutool.core.date.DateUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationType; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationCommonService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.loader.annotation.IocBean; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationCommonServiceImpl + * @Description: TODO + * @Author zxc + * @Date 2022/6/6:10:46 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationCommonServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationCommonService { + + public TheRapyRecuperationCommonServiceImpl(Dao dao) { + super(dao); + } + + + @Override + public boolean canSignUp(String loginName, TheRapyRecuperationType trrt) { + + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + + //每年旅行频率 + Integer travelFrequency = config.getTravelFrequency(); + + //省外几年去一次 + Integer outsideNumber = config.getOutsideNumber(); + + //今年是否参加了? 旅游频率限制 + Cnd cnd = Cnd.NEW(); + cnd.and("loginName", "=", loginName); + cnd.and("YEAR(takePartInTime)", "=", DateUtil.thisYear()); + cnd.and("isTakePartIn", "=", 1); + int joinCount = dao().count(TheRapyRecuperationEnroll.class, cnd); + + if (joinCount == travelFrequency) { + return false; + } + + + //省外 outsideNumber 年内是否去过 + if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue()) { + Cnd lineCnd = cnd.clone(); + lineCnd.and("takePartInLineId", "IS NOT", null); + lineCnd.and(new SqlExpressionGroup().andBetween("YEAR(takePartInTime)", DateUtil.thisYear() - 1, DateUtil.thisYear() - outsideNumber)); + int lineJoinCount = dao().count(TheRapyRecuperationEnroll.class, lineCnd); + return lineJoinCount <= 0; + + } + + + return false; + + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollJoinUserImportServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollJoinUserImportServiceImpl.java new file mode 100644 index 0000000..b60ca03 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollJoinUserImportServiceImpl.java @@ -0,0 +1,79 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollJoinUserImportService; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationEnrollJoinUserImportServiceImpl + * @Description: TODO + * @Author zxc + * @Date 2022/6/14:09:57 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationEnrollJoinUserImportServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationEnrollJoinUserImportService { + public TheRapyRecuperationEnrollJoinUserImportServiceImpl(Dao dao) { + super(dao); + } + + @Override + public List selectLineAndTravelAgencyList(Integer year, String keyword) { + Sql sql = Sqls.create(""" + SELECT + id, + lineName AS label, + '线路' AS `type` + FROM + staff_therapy_line + UNION ALL + SELECT + id, + travelAgencyName AS label, + '旅行社' AS `type` + FROM + staff_therapy_travel_agency + """); + return listMap(sql); + } + + + @Override + public Map> selectLineOrTravelAgency(Integer year) { + Sql lineSql = Sqls.create(""" + SELECT + id, + lineName AS label + FROM + staff_therapy_line + WHERE + `year` = @year + AND createUnionId = @unionId + UNION + SELECT + line.id, + line.lineName AS label + FROM + staff_therapy_line_union_select lus + LEFT JOIN staff_therapy_line line ON line.id = lus.lineId\s + WHERE + line.`year` = @year + AND lus.unionId = @unionId + """); + lineSql.setParam("year", year); + lineSql.setParam("unionId", TherapyContext.getUnionId()); + + Sql travelSql = Sqls.create("SELECT id,travelAgencyName AS label FROM staff_therapy_travel_agency where year = @year"); + travelSql.setParam("year", year); + + return Map.of("lines", listMap(lineSql), "travels", listMap(travelSql)); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollServiceImpl.java new file mode 100644 index 0000000..7d2b5b2 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationEnrollServiceImpl.java @@ -0,0 +1,2376 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.afterturn.easypoi.excel.ExcelExportUtil; +import cn.afterturn.easypoi.excel.entity.ExportParams; +import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.pinyin.PinyinUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.base.service.BaseService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyEmail; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyMessage; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.activity.basic.models.ActivityUserScope; +import com.budwk.app.sys.models.Sys_config; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUnion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyUser; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.common.TherapyRecuperationCommon; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.*; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.TravelAgencyMonthlyEnrollStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.vo.UnionEnrollStatisticsVo; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationEnrollService; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService; +import org.apache.poi.ss.usermodel.Workbook; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; + +import java.io.File; +import java.io.FileOutputStream; +import java.time.LocalDate; +import java.time.Period; +import java.util.*; +import java.util.stream.Collectors; + +/** + * @FileName io.v.nutz.therapyRecuperation.service.impl.TheRapyRecuperationEnrollServiceImpl + * @Description: 疗休养报名service + * @Author zxc + * @Date 2022/6/1:18:46 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationEnrollServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationEnrollService { + + /** + * 代报名校验临时标记,只在当前请求线程内跳过旅行社最多承担人数校验。 + */ + private static final ThreadLocal SKIP_TRAVEL_AGENCY_MAX_UNDERTAKE = new ThreadLocal<>(); + + /** + * 校领导代报名校验临时标记,只在当前请求线程内跳过参加人员范围校验。 + */ + private static final ThreadLocal SKIP_ACTIVITY_USER_SCOPE = new ThreadLocal<>(); + + /** + * 代报名校验临时标记,只在当前请求线程内跳过报名起止时间和调剂报名截止时间校验。 + */ + private static final ThreadLocal SKIP_SIGN_UP_TIME = new ThreadLocal<>(); + + /** + * 代报名校验临时标记,只在当前请求线程内跳过线路最多报名人数校验。 + */ + private static final ThreadLocal SKIP_LINE_MAX_PEOPLE_NUMBER = new ThreadLocal<>(); + + @Inject("refer:staffTherapyDataService") + private BaseService baseService; + + @Inject + private TherapyMessage msgApi; + + @Inject + private TherapyEmail emailUtil; + + @Inject + private com.budwk.app.zhgh.activity.basic.service.ActivityBasicScopeService activityBasicScopeService; + + public TheRapyRecuperationEnrollServiceImpl(Dao dao) { + super(dao); + } + + static Map regionTypeLineMap = new HashMap<>() {{ + put(TheRapyRecuperationType.provinceOutLine.getRegionType(), TheRapyRecuperationType.provinceOutLine); + put(TheRapyRecuperationType.provinceInLine.getRegionType(), TheRapyRecuperationType.provinceInLine); + }}; + + @Inject + private TheRapyRecuperationLineService lineService; + + @Override + public Pagination enrollPageData(PageForm pageForm, Integer year, String unionId, int trrt, Integer lineUnionType, String lineKeyword, Integer signUpStatus) { + Cnd cnd = Cnd.NEW(); + if (List.of(TheRapyRecuperationType.provinceInLine.getValue(), TheRapyRecuperationType.provinceOutLine.getValue()).contains(trrt)) { + Sql lineSql = Sqls.create(""" + SELECT + us.id as usId, + line.id as lineId, + line.serialNumber, + line.lineName, + line.regionalNature, + us.minimumGroupSize, + line.`year`, + us.enable, + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.playStartTime, + us.playEndTime, + us.signUpMode, + us.estimatedFamilyNumbers, + us.estimatedCost, + us.undertakerUnionName, + line.files AS fileId, + usgh.unionname AS usUnionName, + usgh.id AS takePartInUnionId, + u.username AS createUserName, + ta.travelAgencyName, + ta.contact, + ta.contactMobileNumber, + lot.lotName, + lot.lotValue, + lot.activityCost as lotActivityCost, + (select count(1) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as signUpUserFamilyNum, + (select count(1) from staff_therapy_enroll_companion where age >= 18 and trreId in (select id from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as adultFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as familyNumber + FROM + `staff_therapy_line_union_select` us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_lot lot on lot.id = line.lotId + LEFT JOIN staff_therapy_union usgh ON usgh.id = us.unionId + LEFT JOIN staff_therapy_user u ON u.id = line.opBy + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = us.travelAgencyId + $lineCnd + ORDER BY serialNumber ASC, us.playStartTime ASC + """).setParam("year", DateUtil.thisYear()); + Cnd lineCnd = Cnd.NEW(); + lineCnd.and("line.isDisabled", "=", false); + lineCnd.and("us.enable", "=", true); + lineCnd.and("line.regionalNature", "=", TheRapyRecuperationType.typeMap.get(trrt)); + lineCnd.andEX("year(us.selectTime)", "=", year != null ? year : DateUtil.thisYear()); + addMobileLineSignUpStatusCondition(lineCnd, signUpStatus); + // 移动端线路搜索只按当前页签范围内的线路名称过滤,页签条件仍由 trrt 和 lineUnionType 控制。 + if (StrUtil.isNotBlank(lineKeyword)) { + lineCnd.where().andLike("line.lineName", lineKeyword); + } + if (lineUnionType == 1) { + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); +// lineCnd.and("us.isOpen", "=", true); + lineCnd.and("us.unionId", "=", unionId); + } else if (lineUnionType == 2) { + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + lineCnd.and("us.isOpen", "=", true); + lineCnd.and("us.unionId", "=", unionId); + //lineCnd.and("us.unionId", "!=", Vi.getUnionId()); + } else if (lineUnionType == 3) { + // 校工会线路按组织形式 signUpMode=2 查询,不按分工会归属过滤。 + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.FREE.getValue()); + } else if (lineUnionType == 4) { + SqlExpressionGroup unionGroup = new SqlExpressionGroup(); + unionGroup.or("us.unionId", "=", unionId).or("us.isOpen", "=", true); + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + lineCnd.and(unionGroup); + } + lineSql.setVar("lineCnd", lineCnd); + Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), lineSql); + return pagination; + } else if (TheRapyRecuperationType.provinceInTravelAgency.getValue() == trrt) { + cnd.andEX("year", "=", year != null ? year : DateUtil.thisYear()); + cnd.and("isDisabled", "=", false); + cnd.and("ta.signUpTravelAgency", "=", true); + Sql taSql = Sqls.create(""" + select + *, + files as fileId, + (select count(1) from staff_therapy_enroll where takePartInTravelAgencyId=ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where takePartInTravelAgencyId = ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as signUpUserFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInTravelAgencyId=ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as familyNumber + from + staff_therapy_travel_agency ta $condition + """).setParam("year", DateUtil.thisYear()); + taSql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), taSql); + } else if (TheRapyRecuperationType.provinceInHotel.getValue() == trrt) { + cnd.andEX("b.year", "=", year != null ? year : DateUtil.thisYear()); + cnd.and("b.isDisabled", "=", false); + Sql taSql = Sqls.create(""" + select + b.*, + b.files as fileId, + l.lotName, + t.travelAgencyName + from + staff_therapy_base_management b + left join staff_therapy_lot l on l.id = b.lotId + left join staff_therapy_travel_agency t on t.id = b.travelAgencyId + $condition + """); + cnd.asc("sortNumber"); + taSql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), taSql); + } + return new Pagination(); + } + + @Override + public List getSelectLineById(String lineId, String usId, String unionId, int trrt, Integer lineUnionType, Integer signUpStatus) { + Sql lineSql = Sqls.create(""" + SELECT + us.id as usId, + line.id as lineId, + line.serialNumber, + line.lineName, + line.regionalNature, + us.minimumGroupSize, + line.`year`, + us.enable, + us.signUpStartTime, + us.signUpEndTime, + us.adjustSignUpEndTime, + us.changeEndTime, + us.playStartTime, + us.playEndTime, + us.signUpMode, + us.estimatedFamilyNumbers, + line.files AS fileId, + usgh.unionname AS usUnionName, + usgh.id AS takePartInUnionId, + u.username AS createUserName, + ta.travelAgencyName, + us.contact, + us.contactPhone, + lot.lotName, + lot.lotValue, + lot.activityCost as lotActivityCost, + (select count(1) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as signUpUserFamilyNum, + (select count(1) from staff_therapy_enroll_companion where age >= 18 and trreId in (select id from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as adultFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as familyNumber + FROM + `staff_therapy_line_union_select` us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_lot lot on lot.id = line.lotId + LEFT JOIN staff_therapy_union usgh ON usgh.id = us.unionId + LEFT JOIN staff_therapy_user u ON u.id = line.opBy + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId + $lineCnd + ORDER BY us.lineId, playStartTime ASC + """).setParam("year", DateUtil.thisYear()); + Cnd lineCnd = Cnd.NEW(); + if (StrUtil.isNotBlank(usId)) { + lineCnd.and("us.id", "=", usId); + } else { + lineCnd.and("lineId", "=", lineId); + } + lineCnd.and("us.enable", "=", true); + lineCnd.and("year(us.selectTime)", "=", DateUtil.thisYear()); + lineCnd.and("line.regionalNature", "=", TheRapyRecuperationType.typeMap.get(trrt)); + addMobileLineSignUpStatusCondition(lineCnd, signUpStatus); + if (lineUnionType == 1) { + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); +// lineCnd.and("us.isOpen", "=", true); + lineCnd.and("us.unionId", "=", unionId); + } else if (lineUnionType == 2) { + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + lineCnd.and("us.isOpen", "=", true); + lineCnd.and("us.unionId", "=", unionId); + } else if (lineUnionType == 3) { + // 校工会线路按组织形式 signUpMode=2 查询,不按分工会归属过滤。 + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.FREE.getValue()); + } else if (lineUnionType == 4) { + SqlExpressionGroup unionGroup = new SqlExpressionGroup(); + unionGroup.or("us.unionId", "=", unionId).or("us.isOpen", "=", true); + lineCnd.and("us.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + lineCnd.and(unionGroup); + } + lineSql.setVar("lineCnd", lineCnd); + List lineList = (List) Daos.query(dao(), lineSql.toString(), Sqls.callback.maps()); + return lineList; + } + + /** + * 移动端线路列表按报名状态筛选。 + * signUpStatus:0 表示全部,不限制报名时间;1 表示报名中,报名截止或调剂报名截止任一未结束即可展示; + * 2 表示报名已结束,报名截止已过且调剂报名截止为空或已过。 + * + * @param cnd 当前线路查询条件 + * @param signUpStatus 报名状态筛选,0 全部、1 报名中、2 报名已结束 + */ + private void addMobileLineSignUpStatusCondition(Cnd cnd, Integer signUpStatus) { + Integer querySignUpStatus = signUpStatus == null ? 1 : signUpStatus; + if (querySignUpStatus == 0) { + return; + } + Date now = new Date(); + if (querySignUpStatus == 2) { + SqlExpressionGroup adjustEndGroup = new SqlExpressionGroup(); + adjustEndGroup.or("us.adjustSignUpEndTime", "is", null); + adjustEndGroup.or("us.adjustSignUpEndTime", "<", now); + cnd.and("us.signUpEndTime", "<", now); + cnd.and(adjustEndGroup); + return; + } + SqlExpressionGroup signUpDeadlineGroup = new SqlExpressionGroup(); + signUpDeadlineGroup.or("us.signUpEndTime", ">=", now); + signUpDeadlineGroup.or("us.adjustSignUpEndTime", ">=", now); + cnd.and(signUpDeadlineGroup); + } + + @Override + public Object openSignUser(String usId, String travelId, String searchKeyWord) { + List enrolls = new ArrayList<>(); + if (StrUtil.isNotBlank(usId)) { + enrolls = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "=", usId) + .and("isNormal", "=", true) + .and("stateId", "=", 2750) + .and(Cnd.likeEX("userName", searchKeyWord)) + .asc("unionName")); + } + if (StrUtil.isNotBlank(travelId)) { + enrolls = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInTravelAgencyId", "=", travelId) + .and("isNormal", "=", true) + .and("stateId", "=", 2750) + .and(Cnd.likeEX("userName", searchKeyWord)) + .asc("unionName")); + } + enrolls.forEach(item -> { + String firstLetter = PinyinUtil.getFirstLetter(StrUtil.sub(item.getUserName(), 0, 1), ""); + item.setFirstLetter(firstLetter.toUpperCase()); + }); + + Map> listMap = enrolls.stream().collect(Collectors.groupingBy(TheRapyRecuperationEnroll::getFirstLetter)); + + // 对分组结果的键进行排序 + return listMap.entrySet().stream() + .sorted(Comparator.comparing(Map.Entry::getKey)) + .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, + (oldValue, newValue) -> oldValue, LinkedHashMap::new)); + } + + /** + * 校工会代选路线人员搜索,按姓名或工号模糊查询可代报名人员。 + * + * @param keyword 姓名或工号关键字 + * @return 人员下拉列表 + */ + @Override + public List searchProxySignUpUsers(String keyword) { + if (StrUtil.isBlank(keyword)) { + return new ArrayList<>(); + } + Sql sql = Sqls.create(""" + SELECT + u.id, + u.username, + u.loginname, + u.sex, + u.mobile, + u.idcard, + u.unitid, + unit.name AS unitName, + IFNULL(u.unionid, unit.unionid) AS unionId, + un.unionname AS unionName, + CONCAT(u.username, '(', u.loginname, ')-', unit.name) AS label + FROM + staff_therapy_user u + LEFT JOIN staff_therapy_unit unit ON unit.id = u.unitid + LEFT JOIN staff_therapy_union un ON un.id = IFNULL(u.unionid, unit.unionid) + $condition + LIMIT 20 + """); + SqlExpressionGroup keywordGroup = new SqlExpressionGroup(); + keywordGroup.orLike("u.username", keyword).orLike("u.loginname", keyword); + Cnd cnd = Cnd.where("u.disabled", "=", false).and(keywordGroup); + cnd.asc("u.loginname"); + sql.setCondition(cnd); + return listMap(sql); + } + + /** + * 校工会代选线路查询,直接查询校工会和分工会已选择并启用的线路时间段。 + * + * @param year 主页面选择年份 + * @return 线路时间段下拉列表 + */ + @Override + public List getProxySignUpLines(Integer year) { + Sql sql = Sqls.create(""" + SELECT + rlus.id, + rlus.unionId, + rlus.lineId, + rlus.selectUserId, + DATE_FORMAT(rlus.playStartTime, '%Y-%m-%d') AS playStartTime, + DATE_FORMAT(rlus.playEndTime, '%Y-%m-%d') AS playEndTime, + rl.lineName, + rl.regionalNature, + IF(rlus.signUpMode = 2, '校工会', '分工会') AS signUpMode, + lot.lotName, + un.unionname, + ta.travelAgencyName + FROM + staff_therapy_line_union_select rlus + LEFT JOIN staff_therapy_line rl ON rlus.lineId = rl.id + LEFT JOIN staff_therapy_lot lot ON rl.lotId = lot.id + LEFT JOIN staff_therapy_union un ON un.id = rlus.unionId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = IFNULL(rlus.travelAgencyId, rl.travelAgencyId) + $condition + """); + // 代选线路由校工会人工处理,不再要求线路选择记录配置报名开始和结束时间。 + Cnd cnd = Cnd.where("rlus.signUpMode", "in", Lang.array(TheRapyRecuperationSignUpMode.UNION.getValue(), TheRapyRecuperationSignUpMode.FREE.getValue())) + .and("YEAR(rlus.selectTime)", "=", year == null ? DateUtil.thisYear() : year); + cnd.desc("lot.lotValue"); + cnd.desc("rl.lineName"); + cnd.asc("rlus.playStartTime"); + sql.setCondition(cnd); + return listMap(sql); + } + + /** + * 补发未成团通知给已被未成团操作标记删除的报名人。 + * 筛选口径限定为指定报名年度、delFlag=true、isNormal=false,并排除已审核失败状态,避免误发给用户取消或审核失败记录。 + * + * @param year 报名年度,按 signingUptime 所在年份筛选 + * @return 实际调用消息接口的报名记录数量 + */ + @Override + public int resendDeletedFailNotice(Integer year) { + int signUpYear = year != null ? year : DateUtil.thisYear(); + List enrolls = dao().query(TheRapyRecuperationEnroll.class, + Cnd.where("YEAR(signingUptime)", "=", signUpYear) + .and("delFlag", "=", true) + .and("isNormal", "=", false) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL))); + if (Lang.isEmpty(enrolls)) { + return 0; + } + int sendCount = 0; + for (TheRapyRecuperationEnroll enroll : enrolls) { + TheRapyRecuperationLineUnionSelect unionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enroll.getTakePartInLineId()); + if (unionSelect == null) { + continue; + } + TheRapyRecuperationLine line = dao().fetch(TheRapyRecuperationLine.class, unionSelect.getLineId()); + if (line == null) { + continue; + } + String content = "%s老师,您好!您报名的%s线路,出行时间为%s,因报名人数不足未达到成团条件,请尽快进入疗休养管理系统重新选择线路,7月份线路报名截止时间延长至7月4日晚上24点,谢谢!".formatted( + enroll.getUserName(), + line.getLineName(), + DateUtil.format(unionSelect.getPlayStartTime(), "yyyy-MM-dd") + ); + List list = List.of(Map.of("type", "User", "userId", enroll.getLoginName(), "name", enroll.getUserName())); + msgApi.sendMsg(content, list, "疗休养", " IntelligenceMode", TherapyMessage.sendMode.normal.name()); + sendCount++; + } + return sendCount; + } + + /** + * 手动发送所选线路的成团邮件给旅行社。 + * 参数 lineUnionSelectIds 为统计页勾选的线路选择记录 ID;返回值为实际发送邮件的旅行社数量。 + * 该方法复用定时任务的人员名单字段和附件格式,但不校验最少成团人数,用于 superadmin 人工触发指定线路名单发送。 + * + * @param lineUnionSelectIds 线路选择记录 ID 列表 + * @return 实际发送邮件的旅行社数量 + */ + @Override + public int sendTakePartInUserByLineMail(List lineUnionSelectIds) { + if (Lang.isEmpty(lineUnionSelectIds)) { + return 0; + } + Sql sql = Sqls.create(""" + SELECT + e.*, + concat(l.lineName, ifnull(concat('【', ta.travelAgencyName, '】'), ''), ifnull(concat('-', su.unionname), '')) as lineName, + ta.id as travelId, + ta.travelAgencyName, + concat(s.playStartTime, '至' , s.playEndTime) as playTime, + (select count(1) from staff_therapy_enroll_companion ec where ec.trreId = e.id and ec.age >= 18) as companionCount, + (select GROUP_CONCAT(ec.userName, '(', ec.idcard, '、', ec.mobile, ')') from staff_therapy_enroll_companion ec where ec.trreId = e.id) as companionInfo, + u.schoolTime + FROM + staff_therapy_enroll e + LEFT JOIN `staff_therapy_user` u on e.loginName = u.loginname + LEFT JOIN staff_therapy_line_union_select s ON e.takePartInLineId = s.id + left join staff_therapy_line l on l.id = s.lineId + left join staff_therapy_travel_agency ta on ta.id = s.travelAgencyId + left join staff_therapy_union su on su.id = s.unionId + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("takePartInLineId", "in", lineUnionSelectIds); + cnd.and("isNormal", "=", true); + cnd.and("stateId", "=", TheRapyRecuperationState.PASS); + cnd.and("year(signingUptime)", "=", DateUtil.thisYear()); + cnd.asc("l.serialNumber").asc("s.playStartTime").asc("e.signingUptime"); + sql.setCondition(cnd); + List enrolls = listMap(sql); + if (Lang.isEmpty(enrolls)) { + return 0; + } + + enrolls.forEach(item -> item.put("remark", TherapyRecuperationCommon.getRemarkBySchoolTime(item.getString("schoolTime")))); + Map> enrollsMap = enrolls.stream() + .filter(item -> StrUtil.isNotBlank(item.getString("travelId"))) + .collect(Collectors.groupingBy(o -> o.getString("travelId"))); + if (Lang.isEmpty(enrollsMap)) { + return 0; + } + + File tempDir = new File("C:/temp"); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + int sendCount = 0; + List travelAgencyList = dao().query(TheRapyRecuperationTravelAgency.class, Cnd.NEW()); + for (TheRapyRecuperationTravelAgency item : travelAgencyList) { + String email = item.getEmail(); + if (StrUtil.isBlank(email)) { + continue; + } + List userList = enrollsMap.get(item.getId()); + if (Lang.isEmpty(userList)) { + continue; + } + List entityList = new ArrayList<>(); + entityList.add(new ExcelExportEntity("姓名", "userName", 20)); + entityList.add(new ExcelExportEntity("身份证号", "idCard", 20)); + entityList.add(new ExcelExportEntity("联系电话", "mobile", 20)); + entityList.add(new ExcelExportEntity("所属工会", "unionName", 20)); + entityList.add(new ExcelExportEntity("报名线路", "lineName", 50)); + entityList.add(new ExcelExportEntity("出行时间", "playTime", 50)); + ExcelExportEntity entity = new ExcelExportEntity("家属信息", "companionInfo", 50); + entity.setWrap(true); + entityList.add(entity); + entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 50)); + entityList.add(new ExcelExportEntity("备注", "remark", 30)); + + File xls = new File(tempDir, item.getTravelAgencyName() + "疗休养线路出行人员名单.xlsx"); + try (FileOutputStream fileOutputStream = new FileOutputStream(xls)) { + ExportParams exportParams = new ExportParams(); + exportParams.setType(cn.afterturn.easypoi.excel.entity.enmus.ExcelType.XSSF); + Workbook workbook = ExcelExportUtil.exportExcel(exportParams, entityList, userList); + workbook.write(fileOutputStream); + emailUtil.send(email, item.getTravelAgencyName() + "疗休养线路出行人员名单", false, xls); + sendCount++; + } catch (Exception e) { + e.printStackTrace(); + } finally { + if (xls.exists()) { + xls.delete(); + } + } + } + return sendCount; + } + + /** + * 线路报名 + * + * @param enrollInfo 登记信息 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void doSignUpForLine(TheRapyRecuperationEnroll enrollInfo) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + + TherapyUser user = (TherapyUser) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipal(); + + enrollInfo.setLoginName(user.getLoginname()); + enrollInfo.setUserName(user.getUsername()); + enrollInfo.setSex(user.getSex()); + enrollInfo.setUnitName(user.getUnit().getName()); + enrollInfo.setUnionName(user.getUnion().getUnionname()); + enrollInfo.setSelfUnionId(user.getUnion().getId()); + enrollInfo.setSelfUnitId(user.getUnitid()); + enrollInfo.setSigningUptime(new Date()); + enrollInfo.setTakePartIn(false); + enrollInfo.setNormal(true); + + if (lineUnionSelect.getSignUpMode() == TheRapyRecuperationSignUpMode.FREE.getValue()) { + enrollInfo.setTakePartInUnionId(null); + } + + //2023-06-07 省内外线路是否需要审核配置 根据配置来赋报名表的审核状态值☞ + TheRapyRecuperationConfig recuperationConfig = dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + Boolean isSnLine = recuperationConfig.getIsSnLine(); + Boolean isSwLine = recuperationConfig.getIsSwLine(); + + Boolean flag = null; + if (lineInfo.getRegionalNature().equals(TheRapyRecuperationProvinceType.provinceOut.getValue())) { + flag = isSwLine; + } else if (lineInfo.getRegionalNature().equals(TheRapyRecuperationProvinceType.provinceIn.getValue())) { + flag = isSnLine; + } + if (Boolean.TRUE.equals(flag)) { + if (lineUnionSelect.getSignUpMode() == 1) { + if (StrUtil.isNotBlank(enrollInfo.getTakePartInUnionId()) && !enrollInfo.getTakePartInUnionId().equals(enrollInfo.getSelfUnionId())) { + enrollInfo.setStateId(TheRapyRecuperationState.LINEUNIT); + } else { + enrollInfo.setStateId(TheRapyRecuperationState.UNIT); + } + } else { + enrollInfo.setStateId(TheRapyRecuperationState.SCHOOL); + } + } else { + enrollInfo.setStateId(TheRapyRecuperationState.PASS); + } + + if (recuperationConfig.getBedInfo() || recuperationConfig.getFamilyInfo() == 2) { + for (TheRapyRecuperationEnrollCompanion theRapyRecuperationEnrollCompanion : enrollInfo.getCompanionList()) { + insertLinks(theRapyRecuperationEnrollCompanion, "bedInfo"); + } + insertWith(enrollInfo, "companionList|bedInfo"); + } else { + insert(enrollInfo); + } + } + + /** + * 校工会代选线路报名,使用被报名人资料写入报名表,当前登录人仅作为操作人。 + * + * @param enrollInfo 包含被报名人工号和线路选择表id的报名信息 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void doProxySignUpForLine(TheRapyRecuperationEnroll enrollInfo) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + if (lineUnionSelect == null) { + throw Lang.makeThrow("请选择有效的线路"); + } + if (!isProxySignUpLine(lineUnionSelect) || !Boolean.TRUE.equals(lineUnionSelect.getEnable())) { + throw Lang.makeThrow("请选择已启用的报名线路"); + } + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + if (lineInfo == null || lineInfo.isDisabled()) { + throw Lang.makeThrow("所选线路不存在,请重新选择"); + } + TherapyUser proxyUser = dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", enrollInfo.getLoginName())); + if (proxyUser == null) { + throw Lang.makeThrow("请选择有效的代报名人员"); + } + dao().fetchLinks(proxyUser, "unit"); + TherapyUnion proxyUnion = getProxyUserUnion(proxyUser); + if (proxyUser.getUnit() == null || proxyUnion == null) { + throw Lang.makeThrow("代报名人员单位或工会信息不完整,请先维护人员信息"); + } + + // 代报名仅选择人员和线路,报名人基础资料必须按被报名人重新写入,避免被当前操作人覆盖。 + enrollInfo.setId(null); + enrollInfo.setLoginName(proxyUser.getLoginname()); + enrollInfo.setUserName(proxyUser.getUsername()); + enrollInfo.setSex(proxyUser.getSex()); + enrollInfo.setMobile(proxyUser.getMobile()); + enrollInfo.setIdCard(proxyUser.getIdcard()); + enrollInfo.setUnitName(proxyUser.getUnit().getName()); + enrollInfo.setUnionName(proxyUnion.getUnionname()); + enrollInfo.setSelfUnionId(proxyUnion.getId()); + enrollInfo.setSelfUnitId(proxyUser.getUnitid()); + enrollInfo.setTakePartInUnionId(lineUnionSelect.getUnionId()); + enrollInfo.setTakePartInTravelAgencyId(null); + enrollInfo.setTakePartInBaseManagementId(null); + enrollInfo.setSigningUptime(new Date()); + enrollInfo.setTakePartIn(false); + enrollInfo.setNormal(true); + + if (Integer.valueOf(TheRapyRecuperationSignUpMode.FREE.getValue()).equals(lineUnionSelect.getSignUpMode())) { + enrollInfo.setTakePartInUnionId(null); + } + + // 复用线路报名审核状态规则,代报名后仍进入现有校工会审核流程。 + TheRapyRecuperationConfig recuperationConfig = dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + Boolean flag = null; + if (lineInfo.getRegionalNature().equals(TheRapyRecuperationProvinceType.provinceOut.getValue())) { + flag = recuperationConfig.getIsSwLine(); + } else if (lineInfo.getRegionalNature().equals(TheRapyRecuperationProvinceType.provinceIn.getValue())) { + flag = recuperationConfig.getIsSnLine(); + } + if (Boolean.TRUE.equals(flag)) { + if (Integer.valueOf(TheRapyRecuperationSignUpMode.UNION.getValue()).equals(lineUnionSelect.getSignUpMode())) { + if (StrUtil.isNotBlank(enrollInfo.getTakePartInUnionId()) && !enrollInfo.getTakePartInUnionId().equals(enrollInfo.getSelfUnionId())) { + enrollInfo.setStateId(TheRapyRecuperationState.LINEUNIT); + } else { + enrollInfo.setStateId(TheRapyRecuperationState.UNIT); + } + } else { + enrollInfo.setStateId(TheRapyRecuperationState.SCHOOL); + } + } else { + enrollInfo.setStateId(TheRapyRecuperationState.PASS); + } + // 校领导代报名允许录入家属,保存口径与移动端线路报名保持一致。 + saveProxySignUpFamilyInfo(enrollInfo, recuperationConfig); + } + + /** + * 保存校领导代报名记录,按基础设置决定写入家属数量或家属明细。 + * + * @param enrollInfo 代报名信息 + * @param recuperationConfig 疗休养基础设置 + */ + private void saveProxySignUpFamilyInfo(TheRapyRecuperationEnroll enrollInfo, TheRapyRecuperationConfig recuperationConfig) { + if (recuperationConfig != null && Integer.valueOf(2).equals(recuperationConfig.getFamilyInfo())) { + if (enrollInfo.getCompanionList() == null) { + enrollInfo.setCompanionList(new ArrayList<>()); + } + // 详细家属模式与移动端报名保持一致,家属人数由 companionList 统计,主表 familyNumber 不存明细数量。 + enrollInfo.setFamilyNumber(null); + for (TheRapyRecuperationEnrollCompanion companion : enrollInfo.getCompanionList()) { + if (companion.getBedInfo() != null) { + insertLinks(companion, "bedInfo"); + } + } + insertWith(enrollInfo, "companionList|bedInfo"); + return; + } + enrollInfo.setCompanionList(new ArrayList<>()); + if (enrollInfo.getFamilyNumber() == null) { + enrollInfo.setFamilyNumber(0); + } + insert(enrollInfo); + } + + /** + * 获取代报名人员所属工会,兼容用户表直接存工会和单位关联工会两种数据来源。 + * + * @param proxyUser 被报名人 + * @return 被报名人所属工会 + */ + private TherapyUnion getProxyUserUnion(TherapyUser proxyUser) { + String unionId = StrUtil.isNotBlank(proxyUser.getUnionid()) ? proxyUser.getUnionid() : null; + if (StrUtil.isBlank(unionId) && proxyUser.getUnit() != null) { + unionId = proxyUser.getUnit().getUnionId(); + } + if (StrUtil.isBlank(unionId)) { + return null; + } + return dao().fetch(TherapyUnion.class, unionId); + } + + /** + * 判断线路时间段是否允许校工会代选,范围包含分工会和校工会已选择线路。 + * + * @param lineUnionSelect 线路选择时间段 + * @return 是否允许代选 + */ + private boolean isProxySignUpLine(TheRapyRecuperationLineUnionSelect lineUnionSelect) { + if (lineUnionSelect == null) { + return false; + } + Integer signUpMode = lineUnionSelect.getSignUpMode(); + return Integer.valueOf(TheRapyRecuperationSignUpMode.UNION.getValue()).equals(signUpMode) + || Integer.valueOf(TheRapyRecuperationSignUpMode.FREE.getValue()).equals(signUpMode); + } + + /** + * 判断当前请求是否为校工会代报名跳过报名时间校验。 + * + * @return true 表示本次代报名不校验报名起止时间和调剂报名截止时间 + */ + private boolean skipProxySignUpTimeLimit() { + return Boolean.TRUE.equals(SKIP_SIGN_UP_TIME.get()); + } + + /** + * 变更报名 + * + * @param enrollInfo 登记信息 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void updateSignUpLine(TheRapyRecuperationEnroll enrollInfo) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + + TheRapyRecuperationConfig recuperationConfig = dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + + if (lineUnionSelect.getSignUpMode() == TheRapyRecuperationSignUpMode.FREE.getValue()) { + enrollInfo.setTakePartInUnionId(null); + } + + if (recuperationConfig.getBedInfo() || recuperationConfig.getFamilyInfo() == 2) { + dao().clearLinks(enrollInfo, "companionList"); + dao().delete(TheRapyRecuperationEnrollBed.class, enrollInfo.getBedInfoId()); + + dao().insertLinks(enrollInfo, "companionList|bedInfo"); + } + + update(enrollInfo); + //插入变更记录 + TheRapyRecuperationEnrollChangeRecord changeRecord = new TheRapyRecuperationEnrollChangeRecord(); + changeRecord.setEnrollId(enrollInfo.getId()); + changeRecord.setChangeTime(new Date()); + insert(changeRecord); + } + + /** + * 报名旅行社 + * + * @param enrollInfo 登记信息 + */ + @Override + public void doSignUpForTravelAgency(TheRapyRecuperationEnroll enrollInfo) { + + TheRapyRecuperationConfig recuperationConfig = dao().fetch(TheRapyRecuperationConfig.class, Cnd.NEW()); + Boolean travelAudit = recuperationConfig.getTravelAudit(); + enrollInfo.setStateId(travelAudit ? TheRapyRecuperationState.UNIT : TheRapyRecuperationState.PASS); + + TherapyUser user = (TherapyUser) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipal(); + enrollInfo.setLoginName(user.getLoginname()); + enrollInfo.setUserName(user.getUsername()); + enrollInfo.setSex(user.getSex()); + enrollInfo.setUnitName(user.getUnit().getName()); + enrollInfo.setUnionName(user.getUnion().getUnionname()); + enrollInfo.setSelfUnionId(user.getUnion().getId()); + enrollInfo.setSelfUnitId(user.getUnitid()); + enrollInfo.setSigningUptime(new Date()); + enrollInfo.setTakePartIn(false); + enrollInfo.setNormal(true); + + for (TheRapyRecuperationEnrollCompanion theRapyRecuperationEnrollCompanion : enrollInfo.getCompanionList()) { + insertLinks(theRapyRecuperationEnrollCompanion, "bedInfo"); + } + insertWith(enrollInfo, "companionList|bedInfo"); + } + + /** + * 报名酒店 + * + * @param enrollInfo 登记信息 + */ + @Override + public void doSignUpForHotel(TheRapyRecuperationEnroll enrollInfo) { + TherapyUser user = (TherapyUser) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipal(); + enrollInfo.setLoginName(user.getLoginname()); + enrollInfo.setUserName(user.getUsername()); + enrollInfo.setSex(user.getSex()); + enrollInfo.setUnitName(user.getUnit().getName()); + enrollInfo.setUnionName(user.getUnion().getUnionname()); + enrollInfo.setSelfUnionId(user.getUnion().getId()); + enrollInfo.setSelfUnitId(user.getUnitid()); + enrollInfo.setSigningUptime(new Date()); + enrollInfo.setTakePartIn(false); + enrollInfo.setNormal(true); + enrollInfo.setStateId(TheRapyRecuperationState.PASS); + + for (TheRapyRecuperationEnrollCompanion theRapyRecuperationEnrollCompanion : enrollInfo.getCompanionList()) { + insertLinks(theRapyRecuperationEnrollCompanion, "bedInfo"); + } + insertWith(enrollInfo, "companionList|bedInfo"); + } + + /** + * 变更报名 + * + * @param enrollInfo 登记信息 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void updateSignUpHotel(TheRapyRecuperationEnroll enrollInfo) { + + dao().clearLinks(enrollInfo, "companionList"); + dao().delete(TheRapyRecuperationEnrollBed.class, enrollInfo.getBedInfoId()); + + dao().insertLinks(enrollInfo, "companionList|bedInfo"); + + update(enrollInfo); + //插入变更记录 + TheRapyRecuperationEnrollChangeRecord changeRecord = new TheRapyRecuperationEnrollChangeRecord(); + changeRecord.setEnrollId(enrollInfo.getId()); + changeRecord.setChangeTime(new Date()); + insert(changeRecord); + } + + /** + * 变更报名旅行社 + * + * @param enrollInfo 登记信息 + */ + @Override + public void updateSignUpTravelAgency(TheRapyRecuperationEnroll enrollInfo) { + updateIgnoreNull(enrollInfo); + } + + /** + * 验证报名登记信息 + * + * @param enrollInfo 登记信息 + * @param loginName 用户名 + * @return {@link Map}<{@link Boolean}, {@link String}> + */ + @Override + public Map validSignUpInfo(String loginName, TheRapyRecuperationEnroll enrollInfo) { + + //配置信息 + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + + // 判断当前用户是否是被解散的用户:当前年度存在未删除的解散记录即可参与目标线路调剂报名。 + boolean isDismissed = false; + Date adjustSignUpEndTime = null; + if (StrUtil.isNotBlank(enrollInfo.getTakePartInLineId())) { + isDismissed = hasCurrentYearDismissedEnroll(loginName, DateUtil.thisYear()); + + // 如果是被解散的用户,获取调剂报名截止时间 + if (isDismissed) { + TheRapyRecuperationLineUnionSelect unionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + if (unionSelect != null) { + adjustSignUpEndTime = unionSelect.getAdjustSignUpEndTime(); + } + } + } + + // 报名时间校验;校工会代报名只取消时间限制,其他年度频次、省内省外等业务规则继续执行。 + if (!skipProxySignUpTimeLimit()) { + if (isDismissed && adjustSignUpEndTime != null) { + // 被解散的用户:判断是否在调剂报名截止时间内 + Date now = new Date(); + if (DateUtil.compare(now, adjustSignUpEndTime) > 0) { + return Map.of(false, "调剂报名时间已过,抱歉不能报名"); + } + } else { + // 普通用户:判断是否在报名时间内 + Map signUpTimeValidResult = validateConfigSignUpTime(config); + if (signUpTimeValidResult != null) { + return signUpTimeValidResult; + } + } + } + + + Map lineMaxPeopleResult = validLineMaxPeopleNumber(enrollInfo); + if (lineMaxPeopleResult != null) { + return lineMaxPeopleResult; + } + Map travelAgencyMaxResult = validTravelAgencyMaxUndertakeNumber(enrollInfo); + if (travelAgencyMaxResult != null) { + return travelAgencyMaxResult; + } + + TherapyUser user = dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName)); + // 校领导代报名不限制被报名人是否在参加人员范围内,普通报名仍保持原有校验。 + if (!Boolean.TRUE.equals(SKIP_ACTIVITY_USER_SCOPE.get())) { + int count = activityBasicScopeService.isUserInGroup(config.getActivityGroupId(), user.getId()) ? 1 : 0; + if (count == 0) { + return Map.of(false, "抱歉,您不在报名范围内!"); + } + } + + //是否入职满一年 + Sql schoolTimeSql = Sqls.create("select date_format(schoolTime,'%Y-%m-%d') schoolTime from staff_therapy_user where loginName = @loginName").setParam("loginName", loginName); + String schoolTime = (String) Daos.query(dao(), schoolTimeSql.toString(), Sqls.callback.str()); + if (StrUtil.isBlank(schoolTime)) { + return Map.of(false, "请先联系校工会完善您的入校时间后再报名!"); + } + Period period = Period.between(LocalDate.parse(schoolTime), LocalDate.now()); + if (period.getYears() < 1) { + return Map.of(false, "您的入职日期为" + schoolTime + "不满一年无法报名!"); + } + + //每年旅行频率 + Integer travelFrequency = config.getTravelFrequency(); + + //省外几年去一次 + Integer outsideNumber = config.getOutsideNumber(); + + //可以修改几次 + Integer modifyNumber = config.getModifyNumber(); + + //省外最多报名人数 + Integer allLineSignUpNumber = config.getAllLineSignUpNumber(); + + //如果报旅行社 + if (StrUtil.isNotBlank(enrollInfo.getTakePartInTravelAgencyId())) { + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null) { + return oneYear; + } + } + + //如果报酒店 + if (StrUtil.isNotBlank(enrollInfo.getTakePartInBaseManagementId()) && StrUtil.isBlank(enrollInfo.getId())) { + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null) { + return oneYear; + } + } + + Date changeEndTime = null; + + if (StrUtil.isNotBlank(enrollInfo.getTakePartInLineId())) { + //线路信息 + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, enrollInfo.getTakePartInLineId()); + //如果是学校创建的线路 分工会选择模式 查询线路工会所设置的时间 + if (lineInfo.getCreateMode() == TheRapyRecuperationLineCreateMode.SCHOOL.getValue() && + lineInfo.getSignUpMode() == TheRapyRecuperationSignUpMode.UNION.getValue()) { + + TheRapyRecuperationLineUnionSelect selfUnionSelInfo = dao().fetch(TheRapyRecuperationLineUnionSelect.class, + Cnd.where("lineId", "=", enrollInfo.getTakePartInLineId()) + .and("unionId", "=", enrollInfo.getTakePartInUnionId())); + changeEndTime = selfUnionSelInfo.getChangeEndTime(); + } else { + changeEndTime = lineInfo.getChangeEndTime(); + } + TheRapyRecuperationType trrt = regionTypeLineMap.get(lineInfo.getRegionalNature()); + if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue()) { + //省外 outsideNumber 年内是否去过 + int lineJoinCount = this.getCountByOutLine(trrt, loginName, outsideNumber); + if (lineJoinCount > 0) { + return Map.of(false, "省外线路%s年只能报名一次!".formatted(outsideNumber)); + } + //获取今年的所有省外线路 + List lineList = dao().query(TheRapyRecuperationLine.class, Cnd.where("year", "=", DateUtil.thisYear()) + .and("isDisabled", "=", false)); + List lineIds = lineList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()); + //获取这些省外线路的总报名人数 + List enrollList = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", lineIds) + .and("isNormal", "=", true)); + if (enrollList.size() >= allLineSignUpNumber) { + return Map.of(false, "不能报名,省外线路报名人数已达到" + allLineSignUpNumber + "人"); + } + } + } else if (StrUtil.isNotBlank(enrollInfo.getTakePartInBaseManagementId())) { + TheRapyRecuperationBaseManagement baseManagement = dao().fetch(TheRapyRecuperationBaseManagement.class, enrollInfo.getTakePartInBaseManagementId()); + changeEndTime = baseManagement.getChangeEndTime(); + } + + if (StrUtil.isBlank(enrollInfo.getId())) { + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null) { + return oneYear; + } + } + + //变更操作 + if (StrUtil.isNotBlank(enrollInfo.getId())) { + int changeCount = dao().count(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "=", enrollInfo.getId())); + + if (changeCount >= modifyNumber) { + return Map.of(false, "只能变更" + changeCount + "次!"); + } + + if (DateUtil.compare(new Date(), changeEndTime) > 0) { + return Map.of(false, "超过变更截至时间,无法变更!"); + } else { + return Map.of(true, "验证成功"); + } + } + + return Map.of(true, "验证成功"); + } + + @Override + public Map validSignUpInfoForZJXU(String loginName, TheRapyRecuperationEnroll enrollInfo) { + + //配置信息 + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + if (!skipProxySignUpTimeLimit()) { + Map signUpTimeValidResult = validateConfigSignUpTime(config); + if (signUpTimeValidResult != null) { + return signUpTimeValidResult; + } + } + Map lineMaxPeopleResult = validLineMaxPeopleNumber(enrollInfo); + if (lineMaxPeopleResult != null) { + return lineMaxPeopleResult; + } + Map travelAgencyMaxResult = validTravelAgencyMaxUndertakeNumber(enrollInfo); + if (travelAgencyMaxResult != null) { + return travelAgencyMaxResult; + } + + TherapyUser user = dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName)); + // 校领导代报名不限制被报名人是否在参加人员范围内,普通报名仍保持原有校验。 + if (!Boolean.TRUE.equals(SKIP_ACTIVITY_USER_SCOPE.get())) { + int count = activityBasicScopeService.isUserInGroup(config.getActivityGroupId(), user.getId()) ? 1 : 0; + if (count == 0) { + return Map.of(false, "抱歉,您不在报名范围内!"); + } + } + + //每年旅行频率 + Integer travelFrequency = config.getTravelFrequency(); + //省外几年去一次 + Integer outsideNumber = config.getOutsideNumber(); + //可以修改几次 + Integer modifyNumber = config.getModifyNumber(); + //省外最多报名人数 + Integer allLineSignUpNumber = config.getAllLineSignUpNumber(); + //省内起始年份 + Integer provinceStartYear = config.getProvinceStartYear(); + //活动范围 + Integer activityGroupId = config.getActivityGroupId(); + + //线路信息 + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + + Date changeEndTime = lineUnionSelect.getChangeEndTime(); + //Integer estimatedFamilyNumbers = config.getOutsideQuota(); + + TheRapyRecuperationType trrt = regionTypeLineMap.get(lineInfo.getRegionalNature()); + if (StrUtil.isBlank(enrollInfo.getId()) && StrUtil.isNotBlank(enrollInfo.getTakePartInLineId())) { + + //获取标段中的最大费用 + List lotList = dao().query(TheRapyRecuperationLot.class, Cnd.NEW()); + //最大费用 + OptionalInt optionalInt = lotList.stream().mapToInt(TheRapyRecuperationLot::getActivityCost).max(); + int maxCost = optionalInt.isPresent() ? optionalInt.getAsInt() : 0; + //获取当前报名线路对应的标段的费用 + Integer currentLineCost = dao().fetch(TheRapyRecuperationLot.class, lineInfo.getLotId()).getActivityCost(); + + //省外线路判断报名人数 + /*if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue() && estimatedFamilyNumbers != null) { + Map map = validSignCount(enrollInfo, config, estimatedFamilyNumbers, "add"); + if(map != null) { + return map; + } + }*/ + + //获取起始年份到当前时间,是否报名 + Sql sql = Sqls.create(""" + SELECT + r.*, + l.regionalNature, + (select activityCost from staff_therapy_lot where id = l.lotId) as activityCost + FROM + staff_therapy_enroll r + LEFT JOIN staff_therapy_line_union_select us on us.id = r.takePartInLineId + LEFT JOIN staff_therapy_line l ON l.id = us.lineId + $condition + """); + Sql twoYearInSql = sql; + Sql threeYearOutSql = sql; + Sql twoYearOutSql = sql; + Sql nowYearSql = sql; + + Cnd commonCnd = Cnd.NEW(); + commonCnd.and("r.takePartInLineId", "is not", null); + commonCnd.and("loginName", "=", loginName); + commonCnd.and("r.isNormal", "=", true); + commonCnd.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)); + commonCnd.and("signingUptime", "<=", DateUtil.now()); + + //两年参加省内 + Cnd twoYearInCnd = commonCnd.clone(); + twoYearInCnd.and("signingUptime", ">=", provinceStartYear + "-01-01"); + twoYearInCnd.and("regionalNature", "=", "省内"); + twoYearInCnd.and("isTakePartIn", "=", true); + twoYearInSql.setCondition(twoYearInCnd); + List twoYearInMapList = listMap(twoYearInSql); + + //今年是否报名,不管省内省外 + Cnd nowYearCnd = commonCnd.clone(); + nowYearCnd.and("signingUptime", ">=", DateUtil.thisYear() + "-01-01"); + nowYearSql.setCondition(nowYearCnd); + List nowYearMapList = listMap(nowYearSql); + + //两年参加省外 + Cnd twoYearOutCnd = commonCnd.clone(); + twoYearOutCnd.and("signingUptime", ">=", provinceStartYear + "-01-01"); + twoYearOutCnd.and("regionalNature", "=", "省外"); + twoYearOutCnd.and("isTakePartIn", "=", true); + twoYearOutSql.setCondition(twoYearOutCnd); + List twoYearOutMapList = listMap(twoYearOutSql); + + //三年参加省外 + Cnd threeYearOutCnd = commonCnd.clone(); + threeYearOutCnd.and("signingUptime", ">=", (DateUtil.thisYear() - 3) + "-01-01"); + threeYearOutCnd.and("regionalNature", "=", "省外"); + threeYearOutCnd.and("isTakePartIn", "=", true); + threeYearOutSql.setCondition(threeYearOutCnd); + List threeYearOutMapList = listMap(threeYearOutSql); + + //今年是否报名,不管报省内还是省外 + if (nowYearMapList.size() > 0) { + NutMap nowYearMap = nowYearMapList.get(0); + //判断当前报名的线路是否和今年第一次报名的线路重复 + if (nowYearMap.getString("takePartInLineId").equals(lineUnionSelect.getId())) { + return Map.of(false, "您已报名过当前线路,请选择其他线路"); + } + //获取第一次报名线路对应的标段的费用 + int lastLineCost = nowYearMap.getInt("activityCost"); + if ((lastLineCost + currentLineCost) > maxCost) { + return Map.of(false, "您已报名过省内或省外线路"); + } + } + //省内线路判断 + if (trrt.getValue() == TheRapyRecuperationType.provinceInLine.getValue()) { + if (twoYearInMapList.size() == 0 && threeYearOutMapList.size() == 0) { + return Map.of(true, "验证成功"); + } + //查询两年内有没有参加过省外 + if (twoYearOutMapList.size() > 0) { + return Map.of(false, "您近两年已参加过省外线路,不能报名省内线路"); + } + if (twoYearInMapList.size() > 0) { + int hasCost = twoYearInMapList.get(0).getInt("activityCost"); + if ((hasCost + currentLineCost) > maxCost) { + return Map.of(false, "您已参加过省内线路"); + } + } + } + //省外线路判断 + if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue()) { + //两年内参加过省内 + if (twoYearInMapList.size() > 0) { + return Map.of(false, "您近两年已参加过省内线路,不能报名省外线路"); + } + //三年内有没有参加过省外 + if (threeYearOutMapList.size() > 0) { + return Map.of(false, "近三年内您已参加过省外线路,不能再次报名"); + } + //获取今年的所有线路 + List lineList = dao().query(TheRapyRecuperationLine.class, Cnd.where("year", "=", DateUtil.thisYear()) + .and("isDisabled", "=", false)); + List lineIds = lineList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()); + //获取这些线路在选择表中的选择id,因为报名表存的是选择id + List selectList = dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", lineIds)); + List selectIds = selectList.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + //获取这些省外线路的总报名人数 + List enrollList = dao().query(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", selectIds) + .and("isNormal", "=", true).and("signingUptime", "=", DateUtil.thisYear()) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL))); + //活动范围总人数 + List userScopes = activityBasicScopeService.listGroupUserIds(activityGroupId); + int result = (int) Math.floor((double) userScopes.size() / 3); + if (enrollList.size() >= result) { + return Map.of(false, "已报人数超过三分之一,不能报名"); + } + } + } + + //变更操作 + if (StrUtil.isNotBlank(enrollInfo.getId())) { + + /*if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue() && estimatedFamilyNumbers != null) { + Map map = validSignCount(enrollInfo, config, estimatedFamilyNumbers, "edit"); + if(map != null) { + return map; + } + }*/ + + int changeCount = dao().count(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "=", enrollInfo.getId())); + + if (changeCount >= modifyNumber) { + return Map.of(false, "只能变更" + changeCount + "次!"); + } + + if (DateUtil.compare(new Date(), changeEndTime) > 0) { + return Map.of(false, "超过变更截至时间,无法变更!"); + } else { + return Map.of(true, "验证成功"); + } + } + + return Map.of(true, "验证成功"); + } + + @Override + public Map validSignUpInfoForZJNU(String loginName, TheRapyRecuperationEnroll enrollInfo) { + + //配置信息 + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + + // 报名时间校验:普通报名按正常报名起止时间;当前年度存在有效解散记录的人员,允许走目标线路的调剂报名截止时间。 + TheRapyRecuperationLineUnionSelect unionSelect = null; + boolean isDismissed = false; + if (StrUtil.isNotBlank(enrollInfo.getTakePartInLineId())) { + unionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + isDismissed = hasCurrentYearDismissedEnroll(loginName, DateUtil.thisYear()); + } + if (unionSelect == null) { + return Map.of(false, "请配置该线路的报名时间"); + } + Date now = new Date(); + boolean hasSignUpTime = unionSelect.getSignUpStartTime() != null && unionSelect.getSignUpEndTime() != null; + if (!skipProxySignUpTimeLimit()) { + if (hasSignUpTime) { + if (DateUtil.compare(now, unionSelect.getSignUpStartTime()) < 0) { + return Map.of(false, "报名还未开始"); + } + if (DateUtil.compare(now, unionSelect.getSignUpEndTime()) <= 0) { + // 正常报名时间内只放行时间校验,后续人数、范围、频次等业务规则仍继续执行。 + } else if (isDismissed && unionSelect.getAdjustSignUpEndTime() != null) { + if (DateUtil.compare(now, unionSelect.getAdjustSignUpEndTime()) > 0) { + return Map.of(false, "调剂报名时间已过,抱歉不能报名"); + } + } else { + return Map.of(false, "报名时间已过,抱歉不能报名"); + } + } else if (!(isDismissed && unionSelect.getAdjustSignUpEndTime() != null + && DateUtil.compare(now, unionSelect.getAdjustSignUpEndTime()) <= 0)) { + return Map.of(false, "报名还未开始"); + } + } + Map lineMaxPeopleResult = validLineMaxPeopleNumber(enrollInfo); + if (lineMaxPeopleResult != null) { + return lineMaxPeopleResult; + } + Map travelAgencyMaxResult = validTravelAgencyMaxUndertakeNumber(enrollInfo); + if (travelAgencyMaxResult != null) { + return travelAgencyMaxResult; + } + + TherapyUser user = dao().fetch(TherapyUser.class, Cnd.where("loginname", "=", loginName)); + // 校领导代报名不限制被报名人是否在参加人员范围内,普通报名仍保持原有校验。 + if (!Boolean.TRUE.equals(SKIP_ACTIVITY_USER_SCOPE.get())) { + int count = activityBasicScopeService.isUserInGroup(config.getActivityGroupId(), user.getId()) ? 1 : 0; + if (count == 0) { + return Map.of(false, "抱歉,您不在报名范围内!"); + } + } + + //每年旅行频率 + Integer travelFrequency = config.getTravelFrequency(); + //省外几年去一次 + Integer outsideNumber = config.getOutsideNumber(); + //可以修改几次 + Integer modifyNumber = config.getModifyNumber(); + //活动范围 + Integer activityGroupId = config.getActivityGroupId(); + + //如果报旅行社 + if (StrUtil.isNotBlank(enrollInfo.getTakePartInTravelAgencyId())) { + if (StrUtil.isNotBlank(enrollInfo.getId())) { + return Map.of(true, "成功"); + } + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null) { + return oneYear; + } + //自由组团3年只能去2次 + int groupCount = dao().count( + TheRapyRecuperationEnroll.class, + Cnd.where("takePartInTravelAgencyId", "is not", null) + .and("loginName", "=", loginName) + .and("stateId", "=", 2750) + .and("isNormal", "=", true) + .and("year(signingUptime)", "in", Lang.array(config.getProvinceStartYear(), config.getProvinceStartYear() + 1, config.getProvinceStartYear() + 2)) + ); + if (groupCount >= 2) { + return Map.of(false, "自由组团3年内只能参加2次"); + } + } + + //如果报酒店 + if (StrUtil.isNotBlank(enrollInfo.getTakePartInBaseManagementId()) && StrUtil.isBlank(enrollInfo.getId())) { + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null && oneYear.containsKey(false)) { + return oneYear; + } + } + + //线路信息 + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + + Date changeEndTime = lineUnionSelect.getChangeEndTime(); + //线路人数,省外线路最多报名数 + //Integer estimatedFamilyNumbers = config.getOutsideQuota(); + + TheRapyRecuperationType trrt = regionTypeLineMap.get(lineInfo.getRegionalNature()); + + if (StrUtil.isBlank(enrollInfo.getId()) && StrUtil.isNotBlank(enrollInfo.getTakePartInLineId())) { + + Map oneYear = this.validCountOneYear(loginName, travelFrequency); + if (oneYear != null && oneYear.containsKey(false)) { + return oneYear; + } + + //省外线路判断报名人数 + /*if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue() && estimatedFamilyNumbers != null) { + Map map = validSignCount(enrollInfo, config, estimatedFamilyNumbers, "add"); + if(map != null) { + return map; + } + }*/ + + //获取起始年份到当前时间,是否报名 + Sql sql = Sqls.create(""" + SELECT + r.*, + l.regionalNature, + (select activityCost from staff_therapy_lot where id = l.lotId) as activityCost + FROM + staff_therapy_enroll r + LEFT JOIN staff_therapy_line_union_select us on us.id = r.takePartInLineId + LEFT JOIN staff_therapy_line l ON l.id = us.lineId + $condition + """); + Sql threeYearOutSql = sql; + Sql nowYearSql = sql; + + Cnd commonCnd = Cnd.NEW(); + commonCnd.and("r.takePartInLineId", "is not", null); + commonCnd.and("r.takePartInLineId", "!=", ""); + commonCnd.and("loginName", "=", loginName); + commonCnd.and("r.isNormal", "=", true); + commonCnd.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)); + commonCnd.and("signingUptime", "<=", DateUtil.now()); + + //今年是否报名,不管省内省外 + Cnd nowYearCnd = commonCnd.clone(); + nowYearCnd.and("signingUptime", ">=", DateUtil.thisYear() + "-01-01"); + nowYearSql.setCondition(nowYearCnd); + List nowYearMapList = listMap(nowYearSql); + + //三年参加省外 + Cnd threeYearOutCnd = commonCnd.clone(); + threeYearOutCnd.and("signingUptime", ">=", (DateUtil.thisYear() - outsideNumber) + "-01-01"); + threeYearOutCnd.and("regionalNature", "=", "省外"); + threeYearOutCnd.and("isTakePartIn", "=", true); + threeYearOutSql.setCondition(threeYearOutCnd); + List threeYearOutMapList = listMap(threeYearOutSql); + + //今年是否报名,不管报省内还是省外,还是旅行社 + if (nowYearMapList.size() >= travelFrequency) { + return Map.of(false, "您已经选择%s条线路,并审核通过,不能再次选择。".formatted(travelFrequency)); + } + //省外线路判断 + if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue()) { + //三年内有没有参加过省外 + if (threeYearOutMapList.size() > 0) { + return Map.of(false, "近%s年内您已参加过省外线路,不能再次报名".formatted(outsideNumber)); + } + + //zzr2024-04-25修改,删除下面的,取消注释上面的 + List lineList = dao().query(TheRapyRecuperationLine.class, Cnd.NEW().and("isDisabled", "=", false)); + List lineIds = lineList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()); + //获取这些线路在选择表中的选择id,因为报名表存的是选择id + List selectList = dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", lineIds)); + + List userIdList = activityBasicScopeService.listGroupUserIds(activityGroupId); + List userList = dao().query(TherapyUser.class, Cnd.where("unionid", "=", TherapyContext.getUnionId())); + //分工会所有人数 + List unionUserList = userList.stream().filter(v -> userIdList.contains(v.getId())).collect(Collectors.toList()); + + List outLineIdLIst = selectList.stream().filter(v -> v.getSignUpMode() == 2).map(v -> v.getId()).collect(Collectors.toList()); + + //分工会参加省外线路人数 + List selfUnionIdTakePartInUserList = dao().query(TheRapyRecuperationEnroll.class, + Cnd.where("selfUnionId", "=", TherapyContext.getUnionId()).and("takePartInLineId", "in", outLineIdLIst) + .and("YEAR(signingUptime)", "=", DateUtil.thisYear())); + + int selfUnionTakePartNum = selfUnionIdTakePartInUserList.size(); + int selfUnionNum = unionUserList.size(); + + double bili = (double) selfUnionTakePartNum / selfUnionNum; + + /*if (bili >= 0.33) { + return Map.of(false, "本分工会已报省外线路的人数超过三分之一,不能报名"); + }*/ + } + } + + //变更操作 + if (StrUtil.isNotBlank(enrollInfo.getId())) { + + //省外线路判断报名人数 + /*if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue() && estimatedFamilyNumbers != null) { + Map map = validSignCount(enrollInfo, config, estimatedFamilyNumbers, "add"); + if(map != null) { + return map; + } + }*/ + + int changeCount = dao().count(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "=", enrollInfo.getId())); + + if (changeCount >= modifyNumber) { + return Map.of(false, "只能变更" + changeCount + "次!"); + } + + if (isDismissed && lineUnionSelect.getAdjustSignUpEndTime() != null) { + if (DateUtil.compare(new Date(), lineUnionSelect.getAdjustSignUpEndTime()) > 0) { + return Map.of(false, "调剂报名时间已过,无法变更!"); + } + } else if (DateUtil.compare(new Date(), changeEndTime) > 0) { + return Map.of(false, "超过变更截至时间,无法变更!"); + } else { + return Map.of(true, "验证成功"); + } + } + + return Map.of(true, "验证成功"); + } + + public Map validSignCount(TheRapyRecuperationEnroll enrollInfo, TheRapyRecuperationConfig config, int estimatedFamilyNumbers, String type) { + int hasSignNumber = 0;//已经报名的人数 + int currentSignNumber = 1;//当前报名人数,1表示自己,下面的if是加家属人数 + Cnd cnd = Cnd.where("takePartInLineId", "=", enrollInfo.getTakePartInLineId()) + .and("stateId", "in", Lang.array(TheRapyRecuperationState.UNIT, TheRapyRecuperationState.LINEUNIT, TheRapyRecuperationState.SCHOOL, TheRapyRecuperationState.PASS)) + .and("isNormal", "=", true); + //如果是修改,排除自己的报名记录 + if ("edit".equals(type)) { + cnd.and("loginName", "!=", TherapyContext.getPlatformLoginname()); + } + List enrolls = dao().query(TheRapyRecuperationEnroll.class, cnd); + + //1表示在配置页面的家属配置的是数量,2是家属的List + /*if (config.getFamilyInfo() == 1) { + currentSignNumber += enrollInfo.getFamilyNumber() != null ? enrollInfo.getFamilyNumber() : 0; + int sum = enrolls.stream().mapToInt(TheRapyRecuperationEnroll::getFamilyNumber).sum(); + hasSignNumber = enrolls.size() + sum; + } else { + currentSignNumber += enrollInfo.getCompanionList() != null ? enrollInfo.getCompanionList().size() : 0; + List list = enrolls.stream().map(TheRapyRecuperationEnroll::getId).collect(Collectors.toList()); + List companions = dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "=", list)); + hasSignNumber = enrolls.size() + companions.size(); + }*/ + //省外报名限制,不包含家属 +// hasSignNumber += currentSignNumber + enrolls.size(); + if ((currentSignNumber + enrolls.size()) > estimatedFamilyNumbers) { + return Map.of(false, "报名人数已满"); + } else { + return null; + } + } + + /** + * 校工会代选线路报名校验。 + * 代报名复用普通报名规则,仅取消报名时间、线路人数上限和旅行社承载人数上限限制。 + * + * @param loginName 被报名人工号 + * @param enrollInfo 报名信息 + * @return {@link Map}<{@link Boolean}, {@link String}> + */ + @Override + public Map validProxySignUpInfoForLine(String loginName, TheRapyRecuperationEnroll enrollInfo) { + if (StrUtil.isBlank(loginName)) { + return Map.of(false, "请选择代报名人员"); + } + // 代报名必须明确校验被报名人,避免绕过人员下拉后进入后续规则产生空数据。 + if (dao().count(TherapyUser.class, Cnd.where("loginname", "=", loginName)) == 0) { + return Map.of(false, "请选择有效的代报名人员"); + } + if (enrollInfo == null || StrUtil.isBlank(enrollInfo.getTakePartInLineId())) { + return Map.of(false, "请选择报名线路"); + } + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + if (lineUnionSelect == null || !isProxySignUpLine(lineUnionSelect) || !Boolean.TRUE.equals(lineUnionSelect.getEnable())) { + return Map.of(false, "请选择已启用的报名线路"); + } + TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + if (lineInfo == null || lineInfo.isDisabled()) { + return Map.of(false, "所选线路不存在,请重新选择"); + } + Sys_config config = dao().fetch(Sys_config.class, Cnd.where("configKey", "=", "staffTherapyRecuperationVersion")); + if (config == null || StrUtil.isBlank(config.getConfigValue())) { + return Map.of(false, "疗休养版本配置缺失,无法代报名"); + } + + // 代报名只跳过时间和人数上限限制,已报名、年度频次、省内省外等普通规则继续按版本校验。 + SKIP_SIGN_UP_TIME.set(true); + SKIP_LINE_MAX_PEOPLE_NUMBER.set(true); + SKIP_TRAVEL_AGENCY_MAX_UNDERTAKE.set(true); + try { + if ("zjxu".equals(config.getConfigValue())) { + return validSignUpInfoForZJXU(loginName, enrollInfo); + } else if ("zjiet".equals(config.getConfigValue())) { + return validSignUpInfo(loginName, enrollInfo); + } else if ("zjnu".equals(config.getConfigValue())) { + return validSignUpInfoForZJNU(loginName, enrollInfo); + } + return Map.of(false, "未识别的疗休养版本,无法代报名"); + } finally { + SKIP_SIGN_UP_TIME.remove(); + SKIP_LINE_MAX_PEOPLE_NUMBER.remove(); + SKIP_TRAVEL_AGENCY_MAX_UNDERTAKE.remove(); + } + } + + /** + * 校验当前选择线路的最多报名人数,人数口径只统计报名人本人,家属不纳入人数限制。 + * + * @param enrollInfo 报名信息 + * @return 达到线路人数上限时返回提示信息,否则返回 null + */ + private Map validLineMaxPeopleNumber(TheRapyRecuperationEnroll enrollInfo) { + if (Boolean.TRUE.equals(SKIP_LINE_MAX_PEOPLE_NUMBER.get())) { + return null; + } + if (enrollInfo == null || StrUtil.isBlank(enrollInfo.getTakePartInLineId())) { + return null; + } + TheRapyRecuperationLineUnionSelect currentUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + if (currentUnionSelect == null || currentUnionSelect.getMaxPeopleNumber() == null || currentUnionSelect.getMaxPeopleNumber() <= 0) { + return null; + } + + int signedNumber = countLineSignedNumber(currentUnionSelect.getId(), enrollInfo.getId()); + int remainingNumber = currentUnionSelect.getMaxPeopleNumber() - signedNumber; + if (remainingNumber < 1) { + return Map.of(false, "当前线路报名人数已满,请选择其他线路"); + } + return null; + } + + /** + * 校验线路指定旅行社的最多承担人数,人数口径只统计报名人本人,家属不纳入人数限制。 + * + * @param enrollInfo 报名信息 + * @return 达到上限或剩余 1 人提醒时返回提示信息,否则返回 null + */ + @Override + public Map validTravelAgencyMaxUndertakeNumber(TheRapyRecuperationEnroll enrollInfo) { + if (Boolean.TRUE.equals(SKIP_TRAVEL_AGENCY_MAX_UNDERTAKE.get())) { + return null; + } + if (enrollInfo == null || StrUtil.isBlank(enrollInfo.getTakePartInLineId())) { + return null; + } + TheRapyRecuperationLineUnionSelect currentUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + if (currentUnionSelect == null) { + return null; + } + TheRapyRecuperationLine currentLine = dao().fetch(TheRapyRecuperationLine.class, currentUnionSelect.getLineId()); + String travelAgencyId = currentUnionSelect.getTravelAgencyId(); + if (StrUtil.isBlank(travelAgencyId) && currentLine != null) { + travelAgencyId = currentLine.getTravelAgencyId(); + } + if (StrUtil.isBlank(travelAgencyId)) { + return null; + } + TheRapyRecuperationTravelAgency travelAgency = dao().fetch(TheRapyRecuperationTravelAgency.class, travelAgencyId); + if (travelAgency == null || travelAgency.getMaxUndertakeNumber() == null) { + return null; + } + if (travelAgency.getMaxUndertakeNumber() <= 0) { + return Map.of(false, "当前线路所指定的旅行社报名人数已满,请选择其他旅行社旗下的线路"); + } + + List selectIds = getTravelAgencyLineUnionSelectIds(travelAgencyId); + int signedNumber = countTravelAgencySignedNumber(selectIds, enrollInfo.getId()); + int remainingNumber = travelAgency.getMaxUndertakeNumber() - signedNumber; + if (remainingNumber < 1) { + return Map.of(false, "当前线路所指定的旅行社报名人数已满,请选择其他旅行社旗下的线路"); + } + return null; + } + + /** + * 统计当前选择线路的有效报名人数,人数口径只统计报名人本人,家属不纳入人数限制。 + * + * @param lineUnionSelectId 线路选择时间段 ID + * @param excludeEnrollId 编辑报名时需要排除的报名 ID + * @return 已报名人数 + */ + private int countLineSignedNumber(String lineUnionSelectId, String excludeEnrollId) { + if (StrUtil.isBlank(lineUnionSelectId)) { + return 0; + } + Cnd enrollCnd = Cnd.where("takePartInLineId", "=", lineUnionSelectId) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("YEAR(signingUptime)", "=", DateUtil.thisYear()); + if (StrUtil.isNotBlank(excludeEnrollId)) { + enrollCnd.and("id", "!=", excludeEnrollId); + } + List enrollList = dao().query(TheRapyRecuperationEnroll.class, enrollCnd); + if (Lang.isEmpty(enrollList)) { + return 0; + } + return enrollList.size(); + } + + /** + * 查询当前年份中某旅行社承担的所有线路时间段 ID。 + * + * @param travelAgencyId 旅行社 ID + * @return 线路选择时间段 ID 集合 + */ + private List getTravelAgencyLineUnionSelectIds(String travelAgencyId) { + Sql sql = Sqls.create(""" + select + us.id + from + staff_therapy_line_union_select us + left join staff_therapy_line line on line.id = us.lineId + where + ifnull(us.travelAgencyId, line.travelAgencyId) = @travelAgencyId + and year(us.selectTime) = @year + """); + sql.setParam("travelAgencyId", travelAgencyId); + sql.setParam("year", DateUtil.thisYear()); + List selectList = listMap(sql); + return selectList.stream().map(v -> v.getString("id")).collect(Collectors.toList()); + } + + /** + * 统计旅行社当前已承接线路的有效报名人数,人数口径只统计报名人本人,家属不纳入人数限制。 + * + * @param selectIds 线路选择时间段 ID + * @param excludeEnrollId 编辑报名时需要排除的报名 ID + * @return 已报名人数 + */ + private int countTravelAgencySignedNumber(List selectIds, String excludeEnrollId) { + if (Lang.isEmpty(selectIds)) { + return 0; + } + Cnd enrollCnd = Cnd.where("takePartInLineId", "in", selectIds) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("YEAR(signingUptime)", "=", DateUtil.thisYear()); + if (StrUtil.isNotBlank(excludeEnrollId)) { + enrollCnd.and("id", "!=", excludeEnrollId); + } + List enrollList = dao().query(TheRapyRecuperationEnroll.class, enrollCnd); + if (Lang.isEmpty(enrollList)) { + return 0; + } + return enrollList.size(); + } + + /** + * 校验移动端报名是否处于基础设置的统一报名时间范围内。 + * + * @param config 疗休养基础设置 + * @return 不允许报名时返回错误信息,允许报名时返回 null + */ + private Map validateConfigSignUpTime(TheRapyRecuperationConfig config) { + if (config == null || config.getSignUpStartTime() == null || config.getSignUpEndTime() == null) { + return Map.of(false, "请先配置报名时间"); + } + Date now = new Date(); + if (DateUtil.compare(now, config.getSignUpStartTime()) < 0) { + return Map.of(false, "报名未开始,请耐心等待"); + } + if (DateUtil.compare(now, config.getSignUpEndTime()) > 0) { + return Map.of(false, "报名时间已过,抱歉不能报名"); + } + return null; + } + + /** + * 将移动端返回的线路报名时间统一替换为基础设置中的报名时间。 + * + * @param pagination 移动端线路分页数据 + */ + private void useConfigSignUpTime(Pagination pagination) { + if (pagination == null || Lang.isEmpty(pagination.getList())) { + return; + } + useConfigSignUpTime(pagination.getList()); + } + + /** + * 将移动端返回的线路时间段列表统一替换为基础设置中的报名时间。 + * + * @param lineList 移动端线路时间段列表 + */ + private void useConfigSignUpTime(List lineList) { + if (Lang.isEmpty(lineList)) { + return; + } + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + lineList.forEach(line -> useConfigSignUpTime(line, config)); + } + + /** + * 将单条移动端线路详情的报名时间统一替换为基础设置中的报名时间。 + * + * @param line 移动端线路详情 + * @param config 疗休养基础设置 + */ + private void useConfigSignUpTime(NutMap line, TheRapyRecuperationConfig config) { + if (line == null || config == null) { + return; + } + line.setv("signUpStartTime", config.getSignUpStartTime()); + line.setv("signUpEndTime", config.getSignUpEndTime()); + } + + //判断一年报几次 + public Map validCountOneYear(String loginName, int travelFrequency) { + Cnd cnd = Cnd.NEW(); + cnd.and("loginName", "=", loginName); + cnd.and("isNormal", "=", true); + cnd.and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)); + cnd.and("YEAR(signingUptime)", "=", com.budwk.app.base.utils.DateUtil.thisYear()); + int joinCount = dao().count(TheRapyRecuperationEnroll.class, cnd); + + if (joinCount >= travelFrequency) { + List inList = dao().query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省内")); + List unionInSelects = dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", inList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()))); + List outList = dao().query(TheRapyRecuperationLine.class, Cnd.where("regionalNature", "=", "省外")); + List unionOutSelects = dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "in", outList.stream().map(TheRapyRecuperationLine::getId).collect(Collectors.toList()))); + //是否选择省外 + int inCount = dao().count("staff_therapy_enroll", Cnd.where("loginName", "=", loginName) + .and("takePartInLineId", "in", unionInSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList())) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("YEAR(signingUptime)", "=", com.budwk.app.base.utils.DateUtil.thisYear())); + //是否报省外 + int outCount = dao().count("staff_therapy_enroll", Cnd.where("loginName", "=", loginName) + .and("takePartInLineId", "in", unionOutSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList())) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("YEAR(signingUptime)", "=", com.budwk.app.base.utils.DateUtil.thisYear())); + //是否报旅行社 + int travelCount = dao().count("staff_therapy_enroll", Cnd.where("loginName", "=", loginName) + .and(Cnd.exps("takePartInLineId", "is", null).or("takePartInLineId", "=", "")) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("takePartInTravelAgencyId", "is not", null) + .and("YEAR(signingUptime)", "=", com.budwk.app.base.utils.DateUtil.thisYear())); + //是否报酒店 + int hotelCount = dao().count("staff_therapy_enroll", Cnd.where("loginName", "=", loginName) + .and("takePartInLineId", "is", null) + .and("isNormal", "=", true) + .and("stateId", "not in", Lang.array(TheRapyRecuperationState.UNITFAIL, TheRapyRecuperationState.LINEUNITFAIL, TheRapyRecuperationState.SCHOOLFAIL)) + .and("takePartInBaseManagementId", "is not", null) + .and("YEAR(signingUptime)", "=", com.budwk.app.base.utils.DateUtil.thisYear())); + String str = ""; + if (inCount > 0) { + str = "省内线路"; + } else if (outCount > 0) { + str = "省外线路"; + } else if (travelCount > 0) { + str = "旅行社"; + } else if (hotelCount > 0) { + str = "酒店"; + } + return Map.of(false, "一年只能报" + travelFrequency + "次,您已报" + str + ",请先在我的疗休养中删除,方可报名!"); + } + return Map.of(true, "成功"); + } + + public int getCountByOutLine(TheRapyRecuperationType trrt, String loginName, int outsideNumber) { + //省外 outsideNumber 年内是否去过 + if (trrt.getValue() == TheRapyRecuperationType.provinceOutLine.getValue()) { + Sql lineJoinSql = Sqls.create(""" + SELECT + count(*) + FROM + staff_therapy_enroll ren + LEFT JOIN staff_therapy_line rl on ren.takePartInLineId = rl.id + $condition + """); + + Cnd lineCnd = Cnd.NEW(); + lineCnd.and("loginName", "=", loginName); + lineCnd.and("isNormal", "=", true); + lineCnd.and("takePartInLineId", "IS NOT", null); + lineCnd.and("YEAR ( signingUptime )", ">=", com.budwk.app.base.utils.DateUtil.thisYear() - outsideNumber); + lineCnd.and("YEAR ( signingUptime )", "<=", com.budwk.app.base.utils.DateUtil.thisYear() - 1); + lineCnd.and("regionalNature", "=", TheRapyRecuperationType.provinceOutLine.getValue()); + + lineJoinSql.setCondition(lineCnd); + + //lineCnd.and(new SqlExpressionGroup().andBetween("YEAR(signingUptime)", com.budwk.app.base.utils.DateUtil.thisYear() - 1, com.budwk.app.base.utils.DateUtil.thisYear() - outsideNumber)); + return baseService.count(lineJoinSql); + } + return 0; + } + + /** + * 我报名的页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + @Override + public Pagination mySignUpPageData(PageForm pageForm, Cnd cnd, int trrt, Integer year) { + if (List.of( + TheRapyRecuperationType.provinceInLine.getValue(), + TheRapyRecuperationType.provinceOutLine.getValue() + ).contains(trrt)) { + return this.getDataByInLineAndOutLine(pageForm, cnd, trrt, year); + } else if (trrt == TheRapyRecuperationType.provinceInTravelAgency.getValue()) { + return this.getDataByInTravelAgency(pageForm, cnd, trrt, year); + } else if (trrt == TheRapyRecuperationType.provinceInHotel.getValue()) { + return this.getDataByInHotel(pageForm, cnd, trrt, year); + } + return null; + } + + public Pagination getDataByInLineAndOutLine(PageForm pageForm, Cnd cnd, int trrt, Integer year) { + Sql lineSql = Sqls.create(""" + SELECT + e.*, + line.serialNumber, + line.lineName, + line.regionalNature, + line.YEAR, + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.adjustSignUpEndTime, + us.playStartTime, + us.playEndTime, + us.signUpMode, + line.files AS fileId, + gh.unionname AS signUpUnionName, + ta.travelAgencyName, + ta.contact, + ta.contactMobileNumber, + ta.officialWebsite, + (select count(1) from staff_therapy_enroll dismissed where dismissed.loginName = e.loginName and dismissed.isNormal = false and dismissed.delFlag = false and YEAR(dismissed.signingUptime) = YEAR(e.signingUptime)) > 0 as isDismissed, + GROUP_CONCAT(ec.userName) as companionUserNames, + l.lotName, + au.stateName, + au.stateColor + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_union gh ON gh.id = e.takePartInUnionId + LEFT JOIN staff_therapy_line_union_select us on us.id = e.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId + left join staff_therapy_enroll_companion ec on ec.trreId = e.id + left join staff_therapy_lot l on l.id = line.lotId + left join staff_therapy_audit_state au on e.stateId = au.stateId + $condition + GROUP BY e.id + """); + cnd.and("line.regionalNature", "=", TheRapyRecuperationType.typeMap.get(trrt)); + cnd.and("e.isNormal", "=", true); + cnd.andEX("year(e.signingUptime)", "=", year); + + lineSql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), lineSql); + } + + public Pagination getDataByInTravelAgency(PageForm pageForm, Cnd cnd, int trrt, Integer year) { + Sql taSql = Sqls.create(""" + SELECT + e.*, + ta.travelAgencyName, + ta.contact, + ta.contactMobileNumber, + ta.officialWebsite, + ta.files AS fileId, + (select count(1) from staff_therapy_enroll where takePartInTravelAgencyId=ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where takePartInTravelAgencyId = ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year)) as signUpUserFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInTravelAgencyId=ta.id and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as totalFamilyNumber + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = e.takePartInTravelAgencyId + $condition + """).setParam("year", year == null ? DateUtil.thisYear() : year); + cnd.and("e.takePartInTravelAgencyId", "is not", null); + cnd.and("e.isNormal", "=", true); + cnd.and("YEAR(e.signingUptime)", "=", year == null ? DateUtil.thisYear() : year); + taSql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), taSql); + } + + public Pagination getDataByInHotel(PageForm pageForm, Cnd cnd, int trrt, Integer year) { + Sql taSql = Sqls.create(""" + SELECT + e.*, + ta.baseName, + ta.baseContactPerson, + ta.baseContactNumber, + ta.files AS fileId, + l.lotName, + ta.regionalNature, + t.travelAgencyName, + ta.changeEndTime + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_base_management ta ON ta.id = e.takePartInBaseManagementId + LEFT JOIN staff_therapy_lot l on l.id = ta.lotId + LEFT JOIN staff_therapy_travel_agency t on t.id = ta.travelAgencyId + $condition + """); + cnd.and("e.takePartInBaseManagementId", "is not", null); + cnd.and("e.isNormal", "=", true); + cnd.andEX("ta.year", "=", year); + taSql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), taSql); + } + + /** + * 找到报名信息通过id + * + * @param id id + * @return {@link TheRapyRecuperationEnroll} + */ + @Override + public TheRapyRecuperationEnroll findSignUpInfoById(String id) { + TheRapyRecuperationEnroll enroll = fetch(id); + TheRapyRecuperationEnroll recuperationEnroll = fetchLinks(enroll, "companionList|bedInfo"); + recuperationEnroll.getCompanionList().forEach(item -> { + fetchLinks(item, "bedInfo"); + }); + return recuperationEnroll; + } + + /** + * 删除我的报名信息 + * + * @param id id + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void deleteMyEnrollInfoById(String id) { + TheRapyRecuperationEnroll enrollInfo = fetch(id); + dao().clearLinks(enrollInfo, "companionList|bedInfo"); + + if (StrUtil.isNotBlank(enrollInfo.getTakePartInTravelAgencyId())) { + cancelTravelSendEmail(enrollInfo); + } + + delete(id); + dao().clear(TheRapyRecuperationEnrollChangeRecord.class, Cnd.where("enrollId", "=", id)); + if (StrUtil.isBlank(enrollInfo.getTakePartInTravelAgencyId())) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enrollInfo.getTakePartInLineId()); + //TheRapyRecuperationLine lineInfo = dao().fetch(TheRapyRecuperationLine.class, lineUnionSelect.getLineId()); + } + } + + /** + * 校验我的疗休养报名是否允许取消。 + * 线路报名中,当前年度存在有效解散记录的人员按调剂报名截止时间判断;普通报名仍按变更截止时间判断。 + * + * @param id 报名记录id + * @return 为空表示允许取消;非空表示不允许取消的提示文案 + */ + @Override + public String validateCanDeleteMyEnrollInfo(String id) { + TheRapyRecuperationEnroll enroll = dao().fetch(TheRapyRecuperationEnroll.class, id); + if (enroll == null) { + return "报名信息不存在"; + } + + Date changeEndTime = null; + Date adjustSignUpEndTime = null; + + if (StrUtil.isNotBlank(enroll.getTakePartInLineId())) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, enroll.getTakePartInLineId()); + if (lineUnionSelect != null) { + changeEndTime = lineUnionSelect.getChangeEndTime(); + adjustSignUpEndTime = lineUnionSelect.getAdjustSignUpEndTime(); + } + } else if (StrUtil.isNotBlank(enroll.getTakePartInTravelAgencyId())) { + return null; + } else if (StrUtil.isNotBlank(enroll.getTakePartInBaseManagementId())) { + TheRapyRecuperationBaseManagement baseManagement = dao().fetch(TheRapyRecuperationBaseManagement.class, enroll.getTakePartInBaseManagementId()); + if (baseManagement != null) { + changeEndTime = baseManagement.getChangeEndTime(); + } + } + + int signUpYear = enroll.getSigningUptime() != null ? DateUtil.year(enroll.getSigningUptime()) : DateUtil.thisYear(); + boolean isDismissed = StrUtil.isNotBlank(enroll.getTakePartInLineId()) + && hasCurrentYearDismissedEnroll(enroll.getLoginName(), signUpYear); + + if (isDismissed && adjustSignUpEndTime != null) { + if (DateUtil.compare(new Date(), adjustSignUpEndTime) > 0) { + return "调剂报名时间已过,抱歉不能取消"; + } + return null; + } + + if (changeEndTime != null && DateUtil.compare(new Date(), changeEndTime) > 0) { + return "抱歉,当前时间已经不能取消"; + } + return null; + } + + /** + * 手机端线路介绍所有信息 + * + * @param usId usId + * @param usUnionId usUnionId + * @return {@link NutMap} + */ + @Override + public NutMap selectLineAllInfo(String usId, String usUnionId, String year) { + + Sql usLineSql = Sqls.create(""" + SELECT + us.id as usId, + line.id as lineId, + line.lineName, + us.playStartTime, + us.playEndTime, + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.adjustSignUpEndTime, + us.minimumGroupSize, + us.estimatedFamilyNumbers, + us.estimatedCost, + line.content, + l.lotName, + (select COUNT(1) FROM staff_therapy_enroll en WHERE isNormal=true AND en.loginName=@loginname and YEAR(en.signingUptime)=@year) isNormal, + (select COUNT(1) FROM staff_therapy_enroll en WHERE isNormal=false AND en.loginName=@loginname and YEAR(en.signingUptime)=@year) isNormalFalse, + (select count(1) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and YEAR(signingUptime)=@year) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where age >= 18 and trreId in (select id from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and YEAR(signingUptime)=@year)) as signUpUserFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as familyNumber, + ta.travelAgencyName, + us.contactPhone as contactMobileNumber, + us.principal, + us.principalContact, + line.isFamilySignUp + FROM + `staff_therapy_line_union_select` us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_travel_agency ta on ta.id = us.travelAgencyId + LEFT JOIN staff_therapy_lot l on l.id = line.lotId + WHERE if(us.signUpMode = 1, us.unionId = @usUnionId, 1=1) AND us.id = @id + """); + usLineSql.setParam("loginname", TherapyContext.getPrincipalProperty("loginname")); + usLineSql.setParam("year", StrUtil.isNotBlank(year) ? year : DateUtil.thisYear()); + usLineSql.setParam("usUnionId", usUnionId); + usLineSql.setParam("id", usId); + + NutMap lineInfo = fetch(usLineSql); + + // 判断当前用户是否是被解散的用户:当前年度存在未删除的解散记录即可参与调剂报名,不再限定为目标线路选择记录。 + String loginName = TherapyContext.getPrincipalProperty("loginname").toString(); + boolean isDismissed = false; + if (lineInfo != null) { + int signUpYear = StrUtil.isNotBlank(year) ? Integer.parseInt(year) : DateUtil.thisYear(); + isDismissed = hasCurrentYearDismissedEnroll(loginName, signUpYear); + } + lineInfo.setv("isDismissed", isDismissed); + + return lineInfo; + } + + /** + * 判断用户在指定年度是否存在有效解散记录。 + * 有效解散记录指报名记录已被置为 isNormal=false,且未被用户取消删除;用于调剂报名资格判断。 + * + * @param loginName 登录工号 + * @param year 报名年度 + * @return true 表示该年度存在有效解散记录,可继续按目标线路调剂截止时间判断是否允许报名 + */ + private boolean hasCurrentYearDismissedEnroll(String loginName, Integer year) { + if (StrUtil.isBlank(loginName)) { + return false; + } + int signUpYear = year != null ? year : DateUtil.thisYear(); + return dao().count(TheRapyRecuperationEnroll.class, + Cnd.where("loginName", "=", loginName) + .and("isNormal", "=", false) + .and("delFlag", "=", false) + .and("YEAR(signingUptime)", "=", signUpYear)) > 0; + } + + @Override + public List getTheRapyUnions(Integer year, int theRapyRecuperationType) { + //查询某个年份公开线路了的工会 + Sql sql = Sqls.create(""" + SELECT + rr.unionId + FROM + staff_therapy_line_union_select rr left join staff_therapy_line l on rr.lineId = l.id + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("rr.isOpen", "=", true); + cnd.and("year(rr.selectTime)", "=", DateUtil.thisYear()); + cnd.and("rr.unionId", "!=", TherapyContext.getUnionId()); + cnd.and("rr.signUpMode", "=", 1); + cnd.and("l.regionalNature", "=", TheRapyRecuperationType.typeMap.get(theRapyRecuperationType)); + sql.setCondition(cnd); + List listMap = baseService.listMap(sql); + /*List openList = dao().query(TheRapyRecuperationLineUnionSelect.class, Cnd.where("isOpen", "=", true) + .and("signUpMode", "=", 1).and("year(selectTime)", "=", DateUtil.thisYear()).and("unionId", "!=", Vi.getUnionId()));*/ + +// List openList = dao().query(TheRapyRecuperationLineUnionSelect.class, +// Cnd.where("signUpMode", "=", 1).and("year(selectTime)", "=", DateUtil.thisYear())); + + if (Lang.isNotEmpty(listMap)) { + List unionIds = listMap.stream().map(o -> o.getString("unionId")).distinct().collect(Collectors.toList()); + return dao().query(TherapyUnion.class, Cnd.where("id", "in", unionIds)); + } + return new ArrayList<>(); + } + + /** + * 按旅行社和线路出行开始月份统计有效报名数量。 + * 旅行社来源优先取报名记录的自由组团旅行社,其次取线路选择记录旅行社,最后取线路主表旅行社。 + * + * @param year 统计年度,为空时默认当前年度 + * @return 有出行数据的旅行社月份统计,不补齐无数据月份 + */ + @Override + public List getTravelAgencyMonthlyEnrollStatistics(Integer year) { + int queryYear = year == null ? DateUtil.thisYear() : year; + Sql sql = Sqls.create(""" + SELECT + agency.id AS travelAgencyId, + agency.serialNumber, + agency.travelAgencyName, + MONTH(lineu.playStartTime) AS month, + COUNT(DISTINCT enroll.id) AS enrollNumber + FROM + staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + LEFT JOIN staff_therapy_travel_agency agency + ON agency.id = IFNULL(enroll.takePartInTravelAgencyId, IFNULL(lineu.travelAgencyId, line.travelAgencyId)) + WHERE + enroll.isNormal = TRUE + AND enroll.stateId NOT IN (2715, 2725, 2735) + AND YEAR(lineu.playStartTime) = @year + AND lineu.playStartTime IS NOT NULL + AND agency.id IS NOT NULL + GROUP BY + agency.id, + agency.serialNumber, + agency.travelAgencyName, + MONTH(lineu.playStartTime) + ORDER BY + agency.serialNumber ASC, + agency.travelAgencyName ASC, + MONTH(lineu.playStartTime) ASC + """).setParam("year", queryYear); + List countRows = listMap(sql); + return countRows.stream() + .map(row -> new TravelAgencyMonthlyEnrollStatisticsVo() + .setTravelAgencyId(row.getString("travelAgencyId")) + .setTravelAgencyName(row.getString("travelAgencyName")) + .setYear(queryYear) + .setMonth(row.getInt("month")) + .setMonthName(row.getInt("month") + "月") + .setEnrollNumber(Optional.ofNullable(row.getInt("enrollNumber")).orElse(0))) + .collect(Collectors.toList()); + } + + /** + * 将旅行社月度统计转换为 Excel 横向月份列。 + * rows 中每个旅行社一行,month_7、month_8 等字段用于动态月份列取数。 + * + * @param year 统计年度,为空时默认当前年度 + * @return 包含 months 和 rows 的导出数据 + */ + @Override + public NutMap getTravelAgencyMonthlyEnrollExportData(Integer year) { + int queryYear = year == null ? DateUtil.thisYear() : year; + List statisticsList = getTravelAgencyMonthlyEnrollStatistics(queryYear); + TreeSet months = new TreeSet<>(); + LinkedHashMap rowMap = new LinkedHashMap<>(); + statisticsList.forEach(item -> { + months.add(item.getMonth()); + String rowKey = StrUtil.blankToDefault(item.getTravelAgencyId(), item.getTravelAgencyName()); + NutMap row = rowMap.computeIfAbsent(rowKey, key -> new NutMap() + .setv("year", queryYear) + .setv("travelAgencyName", item.getTravelAgencyName())); + row.setv("month_" + item.getMonth(), item.getEnrollNumber()); + }); + return new NutMap() + .setv("months", new ArrayList<>(months)) + .setv("rows", new ArrayList<>(rowMap.values())); + } + + /** + * 按报名人的本人二级工会和线路出行开始月份统计年度有效报名人数。 + * 这里统计本人报名记录数量,不叠加家属人数,避免与旅行社“报名数量”口径不一致。 + * + * @param year 统计年度,为空时默认当前年度 + * @return 有出行数据的二级工会月份统计,不补齐无数据月份 + */ + @Override + public List getUnionEnrollStatistics(Integer year) { + int queryYear = year == null ? DateUtil.thisYear() : year; + Sql sql = Sqls.create(""" + SELECT + enroll.selfUnionId AS unionId, + enroll.unionName AS unionName, + MONTH(lineu.playStartTime) AS month, + COUNT(DISTINCT enroll.id) AS enrollNumber + FROM + staff_therapy_enroll enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + WHERE + enroll.isNormal = TRUE + AND enroll.stateId NOT IN (2715, 2725, 2735) + AND YEAR(lineu.playStartTime) = @year + AND lineu.playStartTime IS NOT NULL + AND enroll.selfUnionId IS NOT NULL + AND enroll.selfUnionId != '' + GROUP BY + enroll.selfUnionId, + enroll.unionName, + MONTH(lineu.playStartTime) + ORDER BY + enroll.unionName ASC, + MONTH(lineu.playStartTime) ASC + """).setParam("year", queryYear); + List countRows = listMap(sql); + return countRows.stream() + .map(row -> new UnionEnrollStatisticsVo() + .setUnionId(row.getString("unionId")) + .setUnionName(row.getString("unionName")) + .setYear(queryYear) + .setMonth(row.getInt("month")) + .setMonthName(row.getInt("month") + "月") + .setEnrollNumber(Optional.ofNullable(row.getInt("enrollNumber")).orElse(0))) + .collect(Collectors.toList()); + } + + /** + * 将二级工会月度统计转换为 Excel 横向月份列。 + * rows 中每个二级工会一行,month_7、month_8 等字段用于动态月份列取数。 + * + * @param year 统计年度,为空时默认当前年度 + * @return 包含 months 和 rows 的导出数据 + */ + @Override + public NutMap getUnionEnrollExportData(Integer year) { + int queryYear = year == null ? DateUtil.thisYear() : year; + List statisticsList = getUnionEnrollStatistics(queryYear); + TreeSet months = new TreeSet<>(); + LinkedHashMap rowMap = new LinkedHashMap<>(); + statisticsList.forEach(item -> { + months.add(item.getMonth()); + String rowKey = StrUtil.blankToDefault(item.getUnionId(), item.getUnionName()); + NutMap row = rowMap.computeIfAbsent(rowKey, key -> new NutMap() + .setv("year", queryYear) + .setv("unionName", item.getUnionName())); + row.setv("month_" + item.getMonth(), item.getEnrollNumber()); + }); + return new NutMap() + .setv("months", new ArrayList<>(months)) + .setv("rows", new ArrayList<>(rowMap.values())); + } + + + /** + * 自由组团取消报名,发送给旅行社 + * + * @param enroll + */ + private void cancelTravelSendEmail(TheRapyRecuperationEnroll enroll) { + TheRapyRecuperationTravelAgency travelAgency = dao().fetch(TheRapyRecuperationTravelAgency.class, Cnd.where("id", "=", enroll.getTakePartInTravelAgencyId())); + NutMap enrollMap = Lang.obj2nutmap(enroll); + enrollMap.setv("travelAgencyName", travelAgency.getTravelAgencyName()); + enrollMap.setv("remark", "该教师自由出行取消报名本旅行社,请从出行名单中移除此教师"); + List nutMaps = new ArrayList<>(); + nutMaps.add(enrollMap); + if (StrUtil.isNotBlank(travelAgency.getEmail())) { + List entityList = new ArrayList<>(); + entityList.add(new ExcelExportEntity("姓名", "userName", 20)); + entityList.add(new ExcelExportEntity("身份证号", "idCard", 20)); + entityList.add(new ExcelExportEntity("联系电话", "mobile", 20)); + entityList.add(new ExcelExportEntity("所属工会", "unionName", 20)); + entityList.add(new ExcelExportEntity("旅行社名称", "travelAgencyName", 20)); + entityList.add(new ExcelExportEntity("备注", "remark", 50)); + + File xls = new File("C:/temp/" + travelAgency.getTravelAgencyName() + "疗休养自由组团出行人员名单.xlsx"); + FileOutputStream fileOutputStream = null; + try { + fileOutputStream = new FileOutputStream(xls); + Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams(), entityList, nutMaps); + workbook.write(fileOutputStream); + fileOutputStream.close(); + emailUtil.send(travelAgency.getEmail(), travelAgency.getTravelAgencyName() + "疗休养自由组团出行人员名单", false, xls); + if (xls.exists()) { + xls.delete(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineAdjustmentServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineAdjustmentServiceImpl.java new file mode 100644 index 0000000..2badc00 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineAdjustmentServiceImpl.java @@ -0,0 +1,140 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineAdjustmentService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.cri.SqlExpressionGroup; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; + +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationLineAdjustmentServiceImpl + * @Description: TODO + * @Author zxc + * @Date 2022/6/10:10:04 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationLineAdjustmentServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationLineAdjustmentService { + + public TheRapyRecuperationLineAdjustmentServiceImpl(Dao dao) { + super(dao); + } + + @Override + public Pagination pageData(PageForm pageForm, Integer year, String lineId, String unionId, String keywords, String regionalNature, String lotId) { + Sql sql = Sqls.create(""" + SELECT + line.id, + line.serialNumber, + line.lineName, + line.regionalNature, + us.minimumGroupSize, + line.`year`, + line.isDisabled, + line.playNumberOfDays, + line.createUnionId, + line.signUpStartTime, + line.signUpEndTime, + line.changeEndTime, + line.signUpMode, + line.createMode, + us.id as usId, + us.playStartTime, + us.playEndTime, + line.files AS fileId, + create_gh.unionname AS createUnionName, + ta.travelAgencyName, + us.unionId, + select_gh.unionname AS selectUnionName, + (select count(1) from staff_therapy_enroll where if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) AND takePartInLineId = us.id and isNormal=true) as signUpUserNum, + (select count(1) from staff_therapy_enroll_companion where trreId in (select id from staff_therapy_enroll where if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) AND takePartInLineId = us.id and isNormal=true)) as signUpUserFamilyNum, + (select ifnull(sum(familyNumber),0) from staff_therapy_enroll where takePartInLineId = us.id and if(us.signUpMode = 1, takePartInUnionId = us.unionId, 1=1) and isNormal = true and stateId not in (2715,2725,2735) and YEAR(signingUptime)=@year) as familyNumber + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId + LEFT JOIN staff_therapy_union create_gh ON create_gh.id = line.createUnionid + LEFT JOIN staff_therapy_union select_gh ON select_gh.id = us.unionId + $condition + """); + sql.setParam("signUpSuccessCode", TheRapyRecuperationState.PASS); + sql.setParam("year", year); + + Cnd cnd = Cnd.NEW(); + cnd.andEX("line.regionalNature","=",regionalNature); + cnd.andEX("line.lotId", "=", lotId); + //cnd.and("line.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); + cnd.and("us.playStartTime", "is not", null); + //cnd.andEX("line.year", "=", year); + cnd.andEX("line.id", "=", lineId); + if (TherapyContext.hasAnyRoles("sysadmin,A06")) { + cnd.andEX("us.unionId", "=", unionId); + cnd.andEX("us.signUpMode", "=", Strings.isNotBlank(unionId) ? 1 : 2); + } else { + cnd.and("us.unionId", "=", TherapyContext.getUnionId()); + cnd.and("us.signUpMode", "=", 1); + } + if (StrUtil.isNotBlank(keywords)) { + SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.orLike("line.lineName", keywords); + seg.orLike("line.serialNumber", keywords); + cnd.and(seg); + } + if (TherapyContext.isNotBlank(pageForm.getPageOrderName(), pageForm.getPageOrderBy())) { + cnd.orderBy(pageForm.getPageOrderName(), pageForm.getPageOrderBy()); + } + cnd.and("year(selectTime)", "=", year); + sql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + @Override + public List findUnionSignUpModeUserList(String lineId, String unionId) { + Sql sql = Sqls.create(""" + SELECT + e.id, + e.loginName, + e.userName, + e.sex, + e.unitName, + e.unionName, + e.signingUptime, + e.isNormal, + count(c.id) as companionCount, + e.familyNumber + FROM + staff_therapy_enroll e + LEFT JOIN staff_therapy_enroll_companion c ON c.trreId = e.id + left join staff_therapy_line_union_select us on e.takePartInLineId = us.id + WHERE + e.takePartInLineId = @lineId + and if(us.signUpMode = 1, e.takePartInUnionId = @unionId, 1=1) + GROUP BY e.id + """); +// AND (e.stateId = @passStateCode or e.stateId is null) + + sql.setParam("lineId", lineId); + sql.setParam("unionId", unionId); + sql.setParam("passStateCode", TheRapyRecuperationState.PASS); + List list = listMap(sql); + for (NutMap rowMap : list) { + Sql companionSql = Sqls.create("select loginName,userName,sex,relation,idCard from staff_therapy_enroll_companion where trreId=@trreId"); + companionSql.setParam("trreId", rowMap.getString("id")); + List companionList = listMap(companionSql); + rowMap.setv("companionList", companionList); + } + return list; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineClusterServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineClusterServiceImpl.java new file mode 100644 index 0000000..d9d741c --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineClusterServiceImpl.java @@ -0,0 +1,262 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationCluster; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationClusterMember; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineClusterService; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.Strings; +import org.nutz.lang.util.NutMap; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationLineClusterServiceImpl + * @Description: 组团 + * @Author zxc + * @Date 2022/6/17:09:04 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationLineClusterServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationLineClusterService { + public TheRapyRecuperationLineClusterServiceImpl(Dao dao) { + super(dao); + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param year 年度 + * @param unionId 工会id + * @param keywords 关键字 + * @return {@link Pagination} + */ + @Override + public Pagination pageData(PageForm pageForm, Integer year, String unionId, String keywords) { +// Sql sql = Sqls.create(""" +// SELECT +// line.id, +// line.serialNumber, +// line.lineName, +// line.regionalNature, +// line.minimumGroupSize, +// line.`year`, +// line.isDisabled, +// line.playNumberOfDays, +// line.createUnionId, +// line.signUpStartTime, +// line.signUpEndTime, +// line.changeEndTime, +// line.createMode, +// line.signUpMode, +// gh.unionname AS ascriptionUnionName, +// gh.id AS ascriptionUnionId, +// u.username AS createUserName, +// ta.travelAgencyName, +// ( SELECT count( 1 ) FROM staff_therapy_enroll WHERE takePartInUnionId = us.unionId AND takePartInLineId = line.id AND stateId = 2750 ) AS signUpUserNum, +// ( +// SELECT +// count( 1 )\s +// FROM +// staff_therapy_enroll_companion\s +// WHERE +// trreId IN ( SELECT id FROM staff_therapy_enroll WHERE takePartInUnionId = us.unionId AND takePartInLineId = line.id AND stateId = 2750 )) AS signUpUserFamilyNum\s +// FROM +// staff_therapy_line_union_select us +// LEFT JOIN staff_therapy_line line ON line.id = us.lineId +// LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId +// LEFT JOIN staff_therapy_union gh ON gh.id = us.unionId +// LEFT JOIN staff_therapy_user u ON u.id = line.opBy +// $usCnd +// UNION ALL +// (SELECT +// line.id, +// line.serialNumber, +// line.lineName, +// line.regionalNature, +// line.minimumGroupSize, +// line.`year`, +// line.isDisabled, +// line.playNumberOfDays, +// line.createUnionId, +// line.signUpStartTime, +// line.signUpEndTime, +// line.changeEndTime, +// line.createMode, +// line.signUpMode, +// gh.unionname AS ascriptionUnionName, +// gh.id AS ascriptionUnionId, +// u.username AS createUserName, +// ta.travelAgencyName, +// ( SELECT count( 1 ) FROM staff_therapy_enroll WHERE takePartInUnionId = line.createUnionId AND takePartInLineId = line.id AND stateId = 2750 ) AS signUpUserNum, +// ( +// SELECT +// count( 1 ) +// FROM +// staff_therapy_enroll_companion +// WHERE +// trreId IN ( SELECT id FROM staff_therapy_enroll WHERE takePartInUnionId = line.createUnionId AND takePartInLineId = line.id AND stateId = 2750 )) AS signUpUserFamilyNum +// FROM +// staff_therapy_line line +// LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId +// LEFT JOIN staff_therapy_union gh ON gh.id = line.createUnionid +// LEFT JOIN staff_therapy_user u ON u.id = line.opBy +// $lineCnd) +// """); + // Cnd lineCnd = Cnd.NEW(); +// //如果是超管 前端传工会id 就不查自由模式的线路 只查线路归属分工会的线路 +// //如果是分工会管理员 不查不查自由模式的线路 由校工会去组团 +// if (ShiroUtil.hasAnyRoles("sysadmin,A06")) { +// if (StrUtil.isNotBlank(unionId)) { +// sql.setVar("lineCnd", Cnd.where("1", "!=", "1")); +// } else { +// lineCnd.andEX("line.year", "=", year); +// lineCnd.andEX("line.createMode", "=", TheRapyRecuperationLineCreateMode.SCHOOL.getValue()); +// lineCnd.andEX("line.signUpMode", "=", TheRapyRecuperationSignUpMode.FREE.getValue()); +// lineCnd.and(Cnd.likeEX("line.lineName", keywords)); +// sql.setVar("lineCnd", lineCnd); +// } +// } else { +// sql.setVar("lineCnd", Cnd.where("1", "!=", "1")); +// } +// +// Cnd usCnd = Cnd.NEW(); +// usCnd.andEX("line.year", "=", year); +// usCnd.andEX("line.signUpMode", "=", TheRapyRecuperationSignUpMode.UNION.getValue()); +// usCnd.and(Cnd.likeEX("line.lineName", keywords)); +// usCnd.andEX("us.unionId", "=", unionId); +// +// //如果只是分工会管理员 us表只查询自己选择的线路 +// if (!ShiroUtil.hasRole("sysadmin")) { +// usCnd.andEX("us.unionId", "=", Vi.getUnionId()); +// } +// +// sql.setVar("usCnd", usCnd); + Sql sql = Sqls.create(""" + SELECT + line.id, + line.serialNumber, + line.lineName, + line.regionalNature, + line.minimumGroupSize, + line.`year`, + line.isDisabled, + line.createUnionId, + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.playStartTime, + us.playEndTime, + line.createMode, + line.signUpMode, + gh.unionname AS ascriptionUnionName, + gh.id AS ascriptionUnionId, + u.username AS createUserName, + ta.travelAgencyName, + ( SELECT count( 1 ) FROM staff_therapy_enroll $summaryCnd ) AS signUpUserNum, + ( SELECT count( 1 ) FROM staff_therapy_enroll_companion WHERE trreId IN ( SELECT id FROM staff_therapy_enroll $summaryCnd )) AS signUpUserFamilyNum + FROM + staff_therapy_line_union_select us + LEFT JOIN staff_therapy_line line ON line.id = us.lineId + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId + LEFT JOIN staff_therapy_union gh ON gh.id = us.unionId + LEFT JOIN staff_therapy_user u ON u.id = line.opBy + $condition + """); + Cnd cnd = Cnd.NEW(); + Cnd summaryCnd = Cnd.NEW(); + summaryCnd.and("isNormal", "=", true); + summaryCnd.and("takePartInLineId", "=", "us.id"); + summaryCnd.and("stateId", "=", TheRapyRecuperationState.PASS); + //如果是超级管理和校工会管理员,查看校工会线路 + if (TherapyContext.hasAnyRoles("sysadmin,A06")) { + cnd.andEX("us.unionId", "=", unionId); + cnd.andEX("us.signUpMode", "=", Strings.isNotBlank(unionId) ? 1 : 2); + }else{ + summaryCnd.and("takePartInUnionId", "=", "us.unionId"); + cnd.andEX("us.signUpMode", "=", 1); + cnd.andEX("us.unionId", "=", TherapyContext.getUnionId()); + } + cnd.andEX("line.year", "=", year); + cnd.and(Cnd.likeEX("line.lineName", keywords)); + sql.setVar("summaryCnd", summaryCnd); + cnd.asc("line.serialNumber"); + sql.setCondition(cnd); + return list(pageForm, sql); + } + + /** + * 查询组团信息 + * + * @param lineId 线路id + * @param lineId 归属工会id + * @return {@link Object} + */ + @Override + public Object findClusterInfo(String lineId, String usUnionId) { + NutMap resMap = NutMap.NEW(); + + Sql sql = Sqls.create(""" + select + loginName, + userName, + sex, + unionName, + (select count(*) from staff_therapy_enroll_companion c where c.trreId = e.id) as companionCount + from + staff_therapy_enroll e + $condition + """); + Cnd cnd = Cnd.NEW(); + cnd.and("takePartInLineId", "=", lineId); + cnd.and("takePartInUnionId", "=", usUnionId); + cnd.and("isNormal", "=", 1); + cnd.and(Cnd.exps("stateId", "is", null).or("stateId", "=", TheRapyRecuperationState.PASS)); + cnd.and("loginName", "not in", Sqls.create("select loginName from staff_therapy_cluster_member where lineId = @lineId AND loginName is not null").setParam("lineId", lineId)); + sql.setCondition(cnd); + List unSelectedUsers = listMap(sql); + + + resMap.put("unSelectedUsers", Map.of("clusterName", "线路未分配人员", "members", unSelectedUsers)); + + List clusters = dao().query(TheRapyRecuperationCluster.class, Cnd.where("lineId", "=", lineId)); + dao().fetchLinks(clusters, null); + + if (Lang.isNotEmpty(clusters)) { + Map clusterMap = clusters.stream().collect(Collectors.toMap(v -> v.getId(), v -> v)); + resMap.putAll(clusterMap); + } + + return resMap; + } + + /** + * 设置组团成员 + * + * @param clusters 集群 + * @param lineId 行id + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void setClusterMembers(List clusters, String lineId) { + dao().clear(TheRapyRecuperationCluster.class, Cnd.where("lineId", "=", lineId)); + dao().clear(TheRapyRecuperationClusterMember.class, Cnd.where("lineId", "=", lineId)); + for (TheRapyRecuperationCluster cluster : clusters) { + insertWith(cluster, "members"); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java new file mode 100644 index 0000000..df0bf1d --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineServiceImpl.java @@ -0,0 +1,643 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.sys.models.Sys_file; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationLineCreateMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationProvinceType; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationSignUpMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.constant.TheRapyRecuperationState; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportExcelMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.mode.TheRapyLineImportImageMode; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnrollCompanion; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLine; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLot; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineService; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import org.nutz.aop.interceptor.ioc.TransAop; +import com.budwk.app.sys.services.SysFileService; +import com.budwk.app.sys.enums.SysFileEngineTypeEnum; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.random.R; +import org.nutz.lang.util.NutMap; +import org.nutz.plugins.wkcache.annotation.CacheRemove; + +import javax.imageio.ImageIO; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationLineServiceImpl + * @Description: TODO + * @Author zxc + * @Date 2022/5/31:09:47 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationLineServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationLineService { + + /** + * 线路导入缩略图允许的图片类型,与系统通用上传图片类型保持一致。 + */ + private static final List LINE_IMPORT_IMAGE_TYPES = List.of("JPG", "JPEG", "PNG", "BMP", "SVG"); + + @Inject + private SysFileService sysFileService; + + public TheRapyRecuperationLineServiceImpl(Dao dao) { + super(dao); + } + + /** + * 删除线路 同时删除分工会选择线路数据 + * + * @param lineId 线路id + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void deleteLine(String lineId) { + delete(lineId); + dao().clear(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "=", lineId)); + deleteLineInfoCache(lineId); + } + + /** + * 添加线路 如果添加人是分工会管理员 同时添加到分工会选择线路表 + * + * @param line 线路 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void addLine(TheRapyRecuperationLine line) { + boolean hasSchoolAdminRole = com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasAnyRoles(List.of("sysadmin", "A06")); + + if (hasSchoolAdminRole) { + line.setCreateUnionId(null); + line.setCreateMode(TheRapyRecuperationLineCreateMode.SCHOOL.getValue()); + insert(line); + } else if (com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.hasRole("H04")) { + line.setCreateUnionId(TherapyContext.getUnionId()); + line.setCreateMode(TheRapyRecuperationLineCreateMode.UNION.getValue()); + insert(line); + + /*if (line.getSignUpMode() == TheRapyRecuperationSignUpMode.UNION.getValue()) { + TheRapyRecuperationLineUnionSelect unionSelect = new TheRapyRecuperationLineUnionSelect(); + unionSelect.setUnionId(line.getCreateUnionId()); + unionSelect.setLineId(line.getId()); + unionSelect.setSelectTime(new Date()); + unionSelect.setSelectUserId((String) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipalProperty("id")); + + unionSelect.setSignUpStartTime(line.getSignUpStartTime()); + unionSelect.setSignUpEndTime(line.getSignUpEndTime()); + unionSelect.setChangeEndTime(line.getChangeEndTime()); + unionSelect.setPlayStartTime(line.getPlayStartTime()); + unionSelect.setPlayEndTime(line.getPlayEndTime()); + + insert(unionSelect); + }*/ + } + } + + /** + * 编辑线路 + * + * @param line 线路 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void editLine(TheRapyRecuperationLine line) { + update(line); + /*if (line.getSignUpMode() == TheRapyRecuperationSignUpMode.UNION.getValue()) { + TheRapyRecuperationLineUnionSelect unionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("lineId", "=", line.getId())); + + if (unionSelect != null) { + unionSelect.setSignUpStartTime(line.getSignUpStartTime()); + unionSelect.setSignUpEndTime(line.getSignUpEndTime()); + unionSelect.setChangeEndTime(line.getChangeEndTime()); + unionSelect.setPlayStartTime(line.getPlayStartTime()); + unionSelect.setPlayEndTime(line.getPlayEndTime()); + updateIgnoreNull(unionSelect); + } else { + TheRapyRecuperationLineUnionSelect insertUnionSelect = new TheRapyRecuperationLineUnionSelect(); + insertUnionSelect.setUnionId(line.getCreateUnionId()); + insertUnionSelect.setLineId(line.getId()); + insertUnionSelect.setSelectTime(new Date()); + insertUnionSelect.setSelectUserId((String) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipalProperty("id")); + + insertUnionSelect.setSignUpStartTime(line.getSignUpStartTime()); + insertUnionSelect.setSignUpEndTime(line.getSignUpEndTime()); + insertUnionSelect.setChangeEndTime(line.getChangeEndTime()); + insertUnionSelect.setPlayStartTime(line.getPlayStartTime()); + insertUnionSelect.setPlayEndTime(line.getPlayEndTime()); + + insert(insertUnionSelect); + } + + } + deleteLineInfoCache(line.getId());*/ + } + + /** + * 开启或关闭线路 + * + * @param lineId 线路id + */ + /** + * 按PC端线路管理页面字段导入线路,并复用新增线路的保存逻辑补齐创建模式与创建工会。 + * + * @param excelList 线路导入模板数据 + * @param imageMap 移动端缩略图列的内嵌图片,key为导入数据行下标 + * @return 导入成功数量 + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public int importLineByPageFields(List excelList, Map imageMap) { + if (excelList == null || excelList.isEmpty()) { + throw new IllegalArgumentException("导入数据不能为空"); + } + + Map safeImageMap = imageMap == null ? Collections.emptyMap() : imageMap; + Set serialNumberSet = new HashSet<>(); + int successCount = 0; + for (int i = 0; i < excelList.size(); i++) { + TheRapyLineImportExcelMode mode = excelList.get(i); + if (isBlankLine(mode)) { + continue; + } + int rowNumber = i + 2; + + // 页面新增线路必填项在导入时同样需要校验,避免生成不可维护的线路数据。 + validImportRequired(mode, rowNumber); + if (!serialNumberSet.add(mode.getSerialNumber())) { + throw new IllegalArgumentException("第" + rowNumber + "行排序号在导入文件中重复"); + } + if (count(Cnd.where("serialNumber", "=", mode.getSerialNumber())) > 0) { + throw new IllegalArgumentException("第" + rowNumber + "行排序号已存在"); + } + + // 移动端缩略图如果是Excel内嵌图片,优先保存图片并使用生成的filepath覆盖单元格文本。 + TheRapyRecuperationLine line = buildLineByImportMode(mode, safeImageMap.get(i), rowNumber); + addLine(line); + successCount++; + } + + if (successCount == 0) { + throw new IllegalArgumentException("导入数据不能为空"); + } + return successCount; + } + + /** + * 判断模板行是否为空行,空行不会参与校验和保存。 + * + * @param mode 模板行数据 + * @return true表示空行 + */ + private boolean isBlankLine(TheRapyLineImportExcelMode mode) { + return mode == null + || (mode.getYear() == null + && mode.getSerialNumber() == null + && StrUtil.isBlank(mode.getLineName()) + && StrUtil.isBlank(mode.getLotId()) + && StrUtil.isBlank(mode.getRegionalNature()) + && StrUtil.isBlank(mode.getTrafficTools()) + && mode.getEstimatedFamilyNumbers() == null + && StrUtil.isBlank(mode.getEstimatedCost()) + && StrUtil.isBlank(mode.getSignUpMode()) + && StrUtil.isBlank(mode.getLineContact()) + && StrUtil.isBlank(mode.getLineContactPhone()) + && StrUtil.isBlank(mode.getContent()) + && StrUtil.isBlank(mode.getIsEnabled()) + && StrUtil.isBlank(mode.getFiles())); + } + + /** + * 校验线路管理页面中要求填写的核心字段。 + * + * @param mode 模板行数据 + * @param rowNumber Excel行号 + */ + private void validImportRequired(TheRapyLineImportExcelMode mode, int rowNumber) { + if (mode.getYear() == null) { + throw new IllegalArgumentException("第" + rowNumber + "行年度不能为空"); + } + if (mode.getSerialNumber() == null) { + throw new IllegalArgumentException("第" + rowNumber + "行排序号不能为空"); + } + if (StrUtil.isBlank(mode.getLineName())) { + throw new IllegalArgumentException("第" + rowNumber + "行线路名称不能为空"); + } + if (StrUtil.isBlank(mode.getLotId())) { + throw new IllegalArgumentException("第" + rowNumber + "行时间标段不能为空"); + } + if (StrUtil.isBlank(mode.getRegionalNature())) { + throw new IllegalArgumentException("第" + rowNumber + "行线路类型不能为空"); + } + if (StrUtil.isBlank(mode.getSignUpMode())) { + throw new IllegalArgumentException("第" + rowNumber + "行组织形式不能为空"); + } + } + + /** + * 将Excel模板行转换成线路实体,字段与PC端线路管理页面保存字段保持一致。 + * + * @param mode 模板行数据 + * @param imageMode 移动端缩略图内嵌图片 + * @param rowNumber Excel行号 + * @return 线路实体 + */ + private TheRapyRecuperationLine buildLineByImportMode(TheRapyLineImportExcelMode mode, TheRapyLineImportImageMode imageMode, int rowNumber) { + TheRapyRecuperationLine line = new TheRapyRecuperationLine(); + line.setYear(mode.getYear()); + line.setSerialNumber(mode.getSerialNumber()); + line.setLineName(mode.getLineName()); + line.setLotId(parseLotId(mode.getLotId(), rowNumber)); + line.setRegionalNature(parseRegionalNature(mode.getRegionalNature(), rowNumber)); + line.setTrafficTools(mode.getTrafficTools()); + line.setMinimumGroupSize(1); + line.setPlayNumberOfDays(1); + line.setEstimatedFamilyNumbers(mode.getEstimatedFamilyNumbers()); + line.setEstimatedCost(mode.getEstimatedCost()); + line.setSignUpMode(parseSignUpMode(mode.getSignUpMode(), rowNumber)); + line.setLineContact(mode.getLineContact()); + line.setLineContactPhone(mode.getLineContactPhone() == null ? null : mode.getLineContactPhone().trim()); + line.setContent(mode.getContent()); + // 页面保存时是否启用为开关默认值,导入未填写时同样按“启用”处理。 + line.setDisabled(StrUtil.isBlank(mode.getIsEnabled()) ? false : parseIsDisabled(mode.getIsEnabled(), rowNumber)); + String importImagePath = saveLineImportImage(imageMode, rowNumber); + line.setFiles(StrUtil.isNotBlank(importImagePath) ? importImagePath : mode.getFiles()); + return line; + } + + /** + * 将Excel时间标段下拉显示值转换为线路表实际保存的标段ID。 + * + * @param lotValue Excel中读取到的标段显示名、标段ID或“显示名_ID” + * @param rowNumber Excel行号 + * @return 时间标段ID + */ + private String parseLotId(String lotValue, int rowNumber) { + String value = StrUtil.trim(lotValue); + if (StrUtil.isBlank(value)) { + throw new IllegalArgumentException("第" + rowNumber + "行时间标段不能为空"); + } + + // EasyPoi的replace可能导入后台值,也可能导入显示名;先兼容“显示名_ID”格式。 + String replaceValue = parseExcelReplaceValue(value); + + TheRapyRecuperationLot lot = dao().fetch(TheRapyRecuperationLot.class, replaceValue); + if (lot == null) { + lot = dao().fetch(TheRapyRecuperationLot.class, Cnd.where("lotName", "=", value)); + } + if (lot == null) { + lot = dao().fetch(TheRapyRecuperationLot.class, Cnd.where("lotName", "=", replaceValue)); + } + if (lot == null) { + lot = dao().fetch(TheRapyRecuperationLot.class, Cnd.where("lotValue", "=", value)); + } + if (lot == null) { + throw new IllegalArgumentException("第" + rowNumber + "行时间标段不正确"); + } + return lot.getId(); + } + + /** + * 拆解EasyPoi下拉替换值,兼容“显示名_后台值”和纯显示名两种导入结果。 + * + * @param value Excel单元格读取值 + * @return 后台值或原始显示名 + */ + private String parseExcelReplaceValue(String value) { + if (StrUtil.isBlank(value)) { + return value; + } + int splitIndex = value.lastIndexOf("_"); + if (splitIndex >= 0 && splitIndex < value.length() - 1) { + return value.substring(splitIndex + 1); + } + return value; + } + + /** + * 将Excel线路类型下拉显示值转换为页面实际保存的省内/省外值。 + * + * @param regionalNature Excel中读取到的线路类型显示名或后台值 + * @param rowNumber Excel行号 + * @return 线路类型后台值 + */ + private String parseRegionalNature(String regionalNature, int rowNumber) { + String value = StrUtil.trim(regionalNature); + if (StrUtil.isBlank(value)) { + throw new IllegalArgumentException("第" + rowNumber + "行线路类型不能为空"); + } + String replaceValue = parseExcelReplaceValue(value); + if (StrUtil.equalsAny(value, TheRapyRecuperationProvinceType.provinceIn.getValue(), "省内线路", "provinceIn") + || StrUtil.equalsAny(replaceValue, TheRapyRecuperationProvinceType.provinceIn.getValue(), "省内线路", "provinceIn")) { + return TheRapyRecuperationProvinceType.provinceIn.getValue(); + } + if (StrUtil.equalsAny(value, TheRapyRecuperationProvinceType.provinceOut.getValue(), "省外线路", "provinceOut") + || StrUtil.equalsAny(replaceValue, TheRapyRecuperationProvinceType.provinceOut.getValue(), "省外线路", "provinceOut")) { + return TheRapyRecuperationProvinceType.provinceOut.getValue(); + } + throw new IllegalArgumentException("第" + rowNumber + "行线路类型不正确"); + } + + /** + * 保存线路导入中的移动端缩略图,并返回与页面上传组件一致的文件路径。 + * + * @param imageMode Excel中提取出的内嵌图片数据 + * @param rowNumber Excel行号 + * @return 上传后的文件路径,为空表示该行没有内嵌图片 + */ + private String saveLineImportImage(TheRapyLineImportImageMode imageMode, int rowNumber) { + if (imageMode == null || imageMode.getData() == null || imageMode.getData().length == 0) { + return null; + } + + String suffix = normalizeLineImportImageSuffix(imageMode.getExtension(), rowNumber); + byte[] uploadBytes = compressLineImportImage(imageMode.getData(), suffix); + String name = StrUtil.isBlank(imageMode.getFileName()) ? "line-thumbnail." + suffix.toLowerCase() : imageMode.getFileName(); + return sysFileService.uploadReturnUrl(SysFileEngineTypeEnum.MINIO.getValue(), name, uploadBytes); + } + + /** + * 校验并标准化导入图片后缀。 + * + * @param extension 图片后缀 + * @param rowNumber Excel行号 + * @return 标准化后的大写图片后缀 + */ + private String normalizeLineImportImageSuffix(String extension, int rowNumber) { + String suffix = StrUtil.blankToDefault(extension, "png").toUpperCase(); + if (!LINE_IMPORT_IMAGE_TYPES.contains(suffix)) { + throw new IllegalArgumentException("第" + rowNumber + "行移动端缩略图仅支持jpg、jpeg、png、bmp、svg图片"); + } + return suffix; + } + + /** + * 按系统通用上传规则压缩导入图片,无法读取的图片直接返回原始字节。 + * + * @param imageBytes 图片原始字节 + * @param suffix 图片后缀 + * @return 待上传的图片字节 + */ + private byte[] compressLineImportImage(byte[] imageBytes, String suffix) { + if ("SVG".equalsIgnoreCase(suffix)) { + return imageBytes; + } + try { + BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(imageBytes)); + if (bufferedImage == null) { + return imageBytes; + } + int size = calculateLineImportImageSize(bufferedImage.getWidth(), bufferedImage.getHeight()); + BufferedImage asBufferedImage = new BufferedImage(Math.max(1, bufferedImage.getWidth() / size), + Math.max(1, bufferedImage.getHeight() / size), BufferedImage.TYPE_INT_RGB); + Graphics2D graphics = asBufferedImage.createGraphics(); + try { + graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + graphics.drawImage(bufferedImage, 0, 0, asBufferedImage.getWidth(), asBufferedImage.getHeight(), null); + } finally { + graphics.dispose(); + } + ByteArrayOutputStream output = new ByteArrayOutputStream(); + boolean writeResult = ImageIO.write(asBufferedImage, suffix.toLowerCase(), output); + return writeResult && output.size() > 0 ? output.toByteArray() : imageBytes; + } catch (Exception e) { + return imageBytes; + } + } + + /** + * 计算图片压缩比例,保持与系统通用上传压缩规则一致。 + * + * @param srcWidth 原图宽度 + * @param srcHeight 原图高度 + * @return 压缩比例 + */ + private int calculateLineImportImageSize(int srcWidth, int srcHeight) { + srcWidth = srcWidth % 2 == 1 ? srcWidth + 1 : srcWidth; + srcHeight = srcHeight % 2 == 1 ? srcHeight + 1 : srcHeight; + int longSide = Math.max(srcWidth, srcHeight); + int shortSide = Math.min(srcWidth, srcHeight); + float scale = ((float) shortSide / longSide); + if (scale <= 1 && scale > 0.5625) { + if (longSide < 1664) { + return 1; + } else if (longSide < 4990) { + return 2; + } else if (longSide > 4990 && longSide < 10240) { + return 4; + } else { + return longSide / 1280; + } + } else if (scale <= 0.5625 && scale > 0.5) { + return longSide / 1280 == 0 ? 1 : longSide / 1280; + } else { + return (int) Math.ceil(longSide / (1280.0 / scale)); + } + } + + /** + * 将页面组织形式下拉值转换为报名模式编码。 + * + * @param signUpMode 组织形式文本或编码 + * @param rowNumber Excel行号 + * @return 报名模式编码 + */ + private Integer parseSignUpMode(String signUpMode, int rowNumber) { + String value = StrUtil.trim(signUpMode); + String replaceValue = parseExcelReplaceValue(value); + if (StrUtil.equalsAny(value, "1", "分工会", "分工会组织") + || StrUtil.equalsAny(replaceValue, "1", "分工会", "分工会组织")) { + return TheRapyRecuperationSignUpMode.UNION.getValue(); + } + if (StrUtil.equalsAny(value, "2", "自由", "校工会", "校工会组织") + || StrUtil.equalsAny(replaceValue, "2", "自由", "校工会", "校工会组织")) { + return TheRapyRecuperationSignUpMode.FREE.getValue(); + } + throw new IllegalArgumentException("第" + rowNumber + "行组织形式不正确"); + } + + /** + * 将页面是否启用下拉值转换为线路禁用状态。 + * + * @param isEnabled 是否启用文本 + * @param rowNumber Excel行号 + * @return true表示禁用,false表示启用 + */ + private boolean parseIsDisabled(String isEnabled, int rowNumber) { + String value = StrUtil.trim(isEnabled); + String replaceValue = parseExcelReplaceValue(value); + if (StrUtil.equalsAny(value, "是", "启用", "true") + || StrUtil.equalsAny(replaceValue, "是", "启用", "true")) { + return false; + } + if (StrUtil.equalsAny(value, "否", "禁用", "false") + || StrUtil.equalsAny(replaceValue, "否", "禁用", "false")) { + return true; + } + throw new IllegalArgumentException("第" + rowNumber + "行是否启用不正确"); + } + + @Override + public void openClosedLine(String lineId) { + //位运算 取反 + update(Chain.makeSpecial("isDisabled", "isDisabled ^ 1"), Cnd.where("id", "=", lineId)); + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + @Override + public Pagination pageData(PageForm pageForm, Cnd cnd) { + Sql sql = Sqls.create(""" + SELECT + line.id, + line.serialNumber, + line.lineName, + line.regionalNature, + line.minimumGroupSize, + line.year, + line.isDisabled, + line.playNumberOfDays, + line.createUnionId, + line.signUpMode, + line.createMode, + line.files AS fileId, + ifnull(gh.unionname, '校工会') AS createUnionName, + u.username AS createUserName, + ta.travelAgencyName, + ta.contact, + ta.contactMobileNumber, + ta.officialWebsite, + line.lotId, + lot.lotName AS lotName, + lot.lotValue AS lotValue + FROM + staff_therapy_line line + LEFT JOIN staff_therapy_travel_agency ta ON ta.id = line.travelAgencyId + LEFT JOIN staff_therapy_union gh ON gh.id = line.createUnionid + LEFT JOIN staff_therapy_user u ON u.id = line.opBy + LEFT JOIN staff_therapy_lot lot on lot.id = line.lotId + $condition + """); + sql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + /** + * 查询线路详细信息 + * + * @param lineId 线路id + * @return {@link String} + */ + @Override + public TheRapyRecuperationLine selectLineInfoById(String lineId) { + return fetchLinks(fetch(lineId), "travelAgency"); + } + + /** + * 根据分工会选择的线路id查询所该线路报名的人 + * + * @param pageForm 页面形式 + * @param lineId 行id + * @return {@link List}<{@link NutMap}> + */ + @Override + public Pagination selectLineUser(PageForm pageForm, String lineId, String unionId) { + Sql sql = Sqls.create(""" + SELECT + line.lineName, + enroll.id, + enroll.loginName, + enroll.userName, + enroll.unionName, + enroll.unitName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_line_union_select lineu ON lineu.id = enroll.takePartInLineId + LEFT JOIN staff_therapy_line line ON line.id = lineu.lineId + WHERE + enroll.takePartInLineId = @takePartInLineId + and enroll.stateId=@stateId + $unionCnd + """).setParam("takePartInLineId", lineId).setParam("stateId", TheRapyRecuperationState.PASS); + if (StrUtil.isNotBlank(unionId) && !TherapyContext.hasAnyRoles("sysadmin")) { + sql.setVar("unionCnd", "and (enroll.takePartInUnionId='%s' or enroll.selfUnionId='%s')".formatted(unionId, unionId)); + //sql.setVar("unionCnd", "and enroll.selfUnionId='%s'".formatted(unionId)); + } + Pagination pagination = listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + List list = pagination.getList(); + list.forEach(v -> { + List companionList = dao().query(TheRapyRecuperationEnrollCompanion.class, Cnd.where("trreId", "=", v.getString("id"))); + for (TheRapyRecuperationEnrollCompanion enrollCompanion : companionList) { + dao().fetchLinks(enrollCompanion, "bedInfo"); + } + v.setv("companionList", companionList); + }); + return pagination; + } + + /** + * 清除线路详细信息 + * + * @param lineId 线路id + */ + @Override + @CacheRemove(cacheKey = "${args[0]}_selectLineInfoById") + public void deleteLineInfoCache(String lineId) { + + } + + /** + * 查看各个分工会设置的时间信息 + * + * @param lineId 线路id + * @return {@link List}<{@link NutMap}> + */ + @Override + public List viewUnionSelectTimeInfo(String lineId) { + Sql sql = Sqls.create(""" + SELECT + us.signUpStartTime, + us.signUpEndTime, + us.changeEndTime, + us.playStartTime, + us.playEndTime, + gh.unionname AS selectUnionName + FROM + `staff_therapy_line_union_select` us + LEFT JOIN staff_therapy_union gh ON gh.id = us.unionId + WHERE us.lineId = @lineId + """); + return listMap(sql); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineUnionSelectServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineUnionSelectServiceImpl.java new file mode 100644 index 0000000..363666b --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationLineUnionSelectServiceImpl.java @@ -0,0 +1,476 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationEnroll; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationLineUnionSelect; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationLineUnionSelectService; +import org.nutz.aop.interceptor.ioc.TransAop; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.dao.util.Daos; +import org.nutz.ioc.aop.Aop; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Lang; +import org.nutz.lang.util.NutMap; + +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationLineUnionSelectServiceImpl + * @Description: 分工会选择线路 + * @Author zxc + * @Date 2022/6/1:10:18 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationLineUnionSelectServiceImpl extends TherapyServiceImpl + implements TheRapyRecuperationLineUnionSelectService { + + public TheRapyRecuperationLineUnionSelectServiceImpl(Dao dao) { + super(dao); + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @param year 年度 + * @param mode 页面模式,1 表示分工会选择线路,2 表示校工会选择线路 + * @return {@link Pagination} + */ + @Override + public Pagination pageData(PageForm pageForm, Cnd cnd, Integer year, Integer mode) { + Sql sql = Sqls.create(""" + select + line.id, + line.serialNumber, + line.lineName, + line.regionalNature, + line.minimumGroupSize, + line.year, + line.isDisabled, + line.playNumberOfDays, + line.createUnionId, + GROUP_CONCAT(us.playStartTime,'至',us.playEndTime,ifnull(concat('(', usTa.travelAgencyName, ')'), '') order by us.playStartTime) as playTimes, + us.signUpStartTime, + us.signUpEndTime, + us.playStartTime, + us.playEndTime, + us.changeEndTime, + us.isOpen, + us.signUpMode, + line.createMode, + gh.unionname AS createUnionName, + u.username AS createUserName, + IFNULL(usTa.travelAgencyName, lineTa.travelAgencyName) AS travelAgencyName, + IFNULL(usTa.contact, lineTa.contact) AS contact, + IFNULL(usTa.contactMobileNumber, lineTa.contactMobileNumber) AS contactMobileNumber, + IFNULL(usTa.officialWebsite, lineTa.officialWebsite) AS officialWebsite, + lot.lotName, + us.unionId as usUnionId, + us.id as usId, + usUnion.unionname as belongUnionName, + (SELECT COUNT(*) FROM staff_therapy_enroll WHERE takePartInLineId=us.id and isNormal=true) applyCount + from + staff_therapy_line line + LEFT JOIN staff_therapy_union gh ON gh.id = line.createUnionid + LEFT JOIN staff_therapy_user u ON u.id = line.opBy + LEFT JOIN staff_therapy_line_union_select us on us.lineId = line.id AND year(selectTime) = @year AND us.signUpMode = @mode $us + LEFT JOIN staff_therapy_travel_agency usTa on usTa.id = us.travelAgencyId + LEFT JOIN staff_therapy_travel_agency lineTa on lineTa.id = line.travelAgencyId + LEFT JOIN staff_therapy_union usUnion on usUnion.id = us.unionId + LEFT JOIN staff_therapy_lot lot on lot.id = line.lotId + $condition + """); + if (Integer.valueOf(1).equals(mode)) { + sql.setVar("us", "AND us.unionId = '%s'".formatted(TherapyContext.getUnionId())); + } + //sql.setParam("unionId", Vi.getUnionId()); + sql.setParam("year", year == null ? DateUtil.thisYear() : year); + sql.setParam("mode", mode == null ? 1 : mode); + + /*SqlExpressionGroup seg = new SqlExpressionGroup(); + seg.or("line.createUnionId", "=", Vi.getUnionId()); + seg.or("line.createMode", "=", TheRapyRecuperationLineCreateMode.SCHOOL.getValue()); + cnd.and(seg);*/ + + cnd.groupBy("line.id"); + sql.setCondition(cnd); + Pagination pagination = list(pageForm, sql); + List list = pagination.getList(); + + List hasSelectLineIds = getHasSelectLineIds(year, mode); + + for (NutMap m : list) { + m.setv("isSelect", hasSelectLineIds.contains(m.getString("id"))); + } + + return pagination; + } + + /** + * 选择线路 + * + * @param us 分工会选择线路信息 + */ + @Override + public void selectLine(TheRapyRecuperationLineUnionSelect us) { + us.setUnionId(TherapyContext.getUnionId()); + us.setSelectTime(new Date()); + us.setSelectUserId((String) com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext.getPrincipalProperty("id")); + if (StrUtil.isBlank(us.getId())) { + insert(us); + } else { + updateIgnoreNull(us); + } + insertOrUpdate(us); + } + + /** + * 保存分工会或校工会选择线路的出行时段。 + * + * @param lineUnionSelects 出行时段列表,mode 用于区分分工会和校工会页面 + */ + @Override + public void selectLineTimes(TheRapyRecuperationLineUnionSelect[] lineUnionSelects) { + if (Lang.isEmpty(lineUnionSelects)) { + return; + } + TheRapyRecuperationLineUnionSelect lineUnionSelect = lineUnionSelects[0]; + validateLineSelectTime(lineUnionSelect.getMode()); + if (StrUtil.isBlank(lineUnionSelect.getLineId())) { + throw Lang.makeThrow("请选择有效的线路"); + } + if (lineUnionSelect.getMode() == null) { + throw Lang.makeThrow("请选择有效的选择线路页面"); + } + + // 组织形式必须以页面入口 mode 为准,避免同时拥有分工会和校工会角色时保存成错误类型。 + int signUpMode = lineUnionSelect.getMode(); + if (!List.of(1, 2).contains(signUpMode)) { + throw Lang.makeThrow("请选择有效的选择线路页面"); + } + + // 清理旧时段时按当前线路、当前工会、当前年份和当前组织形式匹配,避免历史出行时段残留到代选线路下拉。 + List oldUnionSelects = query(Cnd.where("unionId", "=", TherapyContext.getUnionId()) + .and("lineId", "=", lineUnionSelect.getLineId()) + .and("signUpMode", "=", signUpMode) + .and("YEAR(selectTime)", "=", DateUtil.thisYear())); + + TheRapyRecuperationLineUnionSelect oldLineUnionSelect = dao().fetch(TheRapyRecuperationLineUnionSelect.class, Cnd.where("id", "=", lineUnionSelect.getId())); + for (TheRapyRecuperationLineUnionSelect unionSelect : lineUnionSelects) { + unionSelect.setSelectTime(new Date()); + unionSelect.setSelectUserId(TherapyContext.getPlatformUid()); + unionSelect.setUnionId(TherapyContext.getUnionId()); + unionSelect.setIsOpen(Lang.isNotEmpty(oldLineUnionSelect) ? oldLineUnionSelect.getIsOpen() : true); + unionSelect.setSignUpMode(signUpMode); + } + + dao().insertOrUpdate(lineUnionSelects); + List newIds = Arrays.stream(lineUnionSelects).map(TheRapyRecuperationLineUnionSelect::getId).collect(Collectors.toList()); + List deleteIds = oldUnionSelects.stream().map(TheRapyRecuperationLineUnionSelect::getId).filter(v -> !newIds.contains(v)).collect(Collectors.toList()); + if (Lang.isNotEmpty(deleteIds)) { + clear(Cnd.where("id", "in", deleteIds)); + } + } + + /** + * 已经选择的线路ids + * + * @param year 选择年份 + * @param mode 页面模式,1 表示分工会选择线路,2 表示校工会选择线路 + * @return {@link List}<{@link String}> + */ + @Override + public List getHasSelectLineIds(Integer year, Integer mode) { + Sql sql = Sqls.create(""" + select lineId from staff_therapy_line_union_select + where signUpMode = @mode + $userCnd + $unionCnd + and year(selectTime) = @year + """); + sql.setParam("mode", mode == null ? 1 : mode); + sql.setParam("year", year == null ? DateUtil.thisYear() : year); + sql.setVar("userCnd", ""); + sql.setVar("unionCnd", ""); + if (Integer.valueOf(1).equals(mode == null ? 1 : mode)) { + sql.setVar("unionCnd", "and unionId = @unionId"); + sql.setParam("unionId", TherapyContext.getUnionId()); + } + List lineIdsMap = (List) Daos.query(dao(), sql.toString(), Sqls.callback.maps()); + return lineIdsMap.stream().map(v -> v.getString("lineId")).collect(Collectors.toList()); + } + + /** + * 设置的活动时间信息 + * + * @param lineId 行id + * @return {@link Object} + */ + @Override + public Object selectLineInfo(String lineId, String unionId, Integer mode, Integer year) { + Sql sql; + + sql = Sqls.create(""" + select + us.id, + lineId, + signUpStartTime, + signUpEndTime, + changeEndTime, + adjustSignUpEndTime, + playStartTime, + playEndTime, + us.contact, + us.contactPhone, + us.principal, + us.principalContact, + minimumGroupSize, + trafficTools, + estimatedCost, + estimatedFamilyNumbers, + maxPeopleNumber, + us.travelAgencyId, + signUpMode, + enable, + ta.travelAgencyName + from + staff_therapy_line_union_select us + left join staff_therapy_travel_agency ta on ta.id = us.travelAgencyId + where unionId = @unionId + and lineId = @lineId + and signUpMode = @mode + and year(selectTime) = @year + ORDER BY signUpStartTime,playStartTime ASC + """); + sql.setParam("unionId", unionId); + sql.setParam("lineId", lineId); + sql.setParam("mode", mode); + sql.setParam("year", year == null ? DateUtil.thisYear() : year); + return listMap(sql); + + +// TheRapyRecuperationLine line = dao().fetch(TheRapyRecuperationLine.class, lineId); +// if (line.getSignUpMode() == TheRapyRecuperationSignUpMode.UNION.getValue()) { +// sql = Sqls.create(""" +// select +// id, +// lineId, +// signUpStartTime, +// signUpEndTime, +// changeEndTime, +// playStartTime, +// playEndTime, +// contact, +// contactPhone +// from +// staff_therapy_line_union_select +// where unionId = @unionId +// and lineId = @lineId +// ORDER BY signUpStartTime ASC +// """); +// sql.setParam("unionId", unionId); +// sql.setParam("lineId", lineId); +// return listMap(sql); +// } else { +// sql = Sqls.create(""" +// select +// id, +// signUpStartTime, +// signUpEndTime, +// changeEndTime, +// playStartTime, +// playEndTime +// from +// staff_therapy_line +// where id = @lineId +// """); +// sql.setParam("lineId", lineId); +// return listMap(sql); +// } + + } + + /** + * 设置线路时间信息 + * + * @param unionSelect 联盟选择 + */ + @Override + public void setLineInfo(TheRapyRecuperationLineUnionSelect unionSelect) { + dao().updateIgnoreNull(unionSelect); + } + + /** + * 查询某个分工会设置的线路时间信息 + * + * @param lineId 行id + * @param usUnionId 我们工会id + * @return {@link NutMap} + */ + @Override + public TheRapyRecuperationLineUnionSelect findUsLineInfo(String lineId, String usUnionId) { + return dao().fetch(TheRapyRecuperationLineUnionSelect.class, + Cnd.where("lineId", "=", lineId) + .and("unionId", "=", usUnionId)); + } + + /** + * 分工会取消选择线路 + * + * @param usId union_select 主键id + */ + @Override + @Aop(TransAop.READ_COMMITTED) + public void deSelect(String usId) { + TheRapyRecuperationLineUnionSelect lineUnionSelect = fetch(usId); + Cnd enrollCnd = Cnd.where("takePartInUnionId", "=", lineUnionSelect.getUnionId()); + enrollCnd.and("takePartInLineId", "=", lineUnionSelect.getLineId()); + dao().clear(TheRapyRecuperationEnroll.class, enrollCnd); + delete(usId); + } + + /** + * 选择线路时间由基础设置统一控制;校工会选择线路 mode=2 按业务要求不受该时间限制。 + * + * @param mode 选择线路页面类型,1 表示分工会选择线路,2 表示校工会选择线路 + */ + @Override + public void validateLineSelectTime(Integer mode) { + if (Integer.valueOf(2).equals(mode)) { + return; + } + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + if (config == null || config.getLineSelectStartTime() == null || config.getLineSelectEndTime() == null) { + return; + } + Date now = new Date(); + if (DateUtil.compare(now, config.getLineSelectStartTime()) < 0) { + throw Lang.makeThrow("选择线路还未开始"); + } + if (DateUtil.compare(now, config.getLineSelectEndTime()) > 0) { + throw Lang.makeThrow("选择线路已结束"); + } + } + + /** + * 管理员保存指定分工会已选择线路的全部时间段信息。 + * + * @param lineUnionSelects 出行时间段列表,每项包含报名时间、出行时间、旅行社、联系人、人数和启用状态等字段 + * @param lineId 线路 ID,只允许保存该线路下的时间段 + * @param unionId 分工会 ID,只允许保存该分工会选择的时间段 + * @param year 年度,按选择记录 selectTime 所属年份定位数据 + */ + @Override + public void adminSaveLineTimes(TheRapyRecuperationLineUnionSelect[] lineUnionSelects, String lineId, String unionId, Integer year) { + if (Lang.isEmpty(lineUnionSelects)) { + throw Lang.makeThrow("请至少保留一个出行时间段"); + } + Integer queryYear = year == null ? DateUtil.thisYear() : year; + List oldUnionSelects = query(Cnd.where("lineId", "=", lineId) + .and("unionId", "=", unionId) + .and("signUpMode", "=", 1) + .and("YEAR(selectTime)", "=", queryYear)); + Map oldSelectMap = oldUnionSelects.stream() + .filter(v -> StrUtil.isNotBlank(v.getId())) + .collect(Collectors.toMap(TheRapyRecuperationLineUnionSelect::getId, v -> v)); + + Date newSelectTime = DateUtil.parse(queryYear + "-01-01 00:00:00"); + for (TheRapyRecuperationLineUnionSelect unionSelect : lineUnionSelects) { + validateAdminLineTime(unionSelect); + if (StrUtil.isNotBlank(unionSelect.getId()) && !oldSelectMap.containsKey(unionSelect.getId())) { + throw Lang.makeThrow("出行时间段不存在或不属于当前线路"); + } + unionSelect.setLineId(lineId); + unionSelect.setUnionId(unionId); + unionSelect.setSignUpMode(1); + unionSelect.setSelectTime(StrUtil.isNotBlank(unionSelect.getId()) && oldSelectMap.containsKey(unionSelect.getId()) + ? oldSelectMap.get(unionSelect.getId()).getSelectTime() + : newSelectTime); + if (StrUtil.isNotBlank(unionSelect.getId()) && oldSelectMap.containsKey(unionSelect.getId())) { + TheRapyRecuperationLineUnionSelect oldSelect = oldSelectMap.get(unionSelect.getId()); + unionSelect.setIsOpen(oldSelect.getIsOpen()); + unionSelect.setMinimumGroupSize(oldSelect.getMinimumGroupSize()); + } + if (unionSelect.getIsOpen() == null) { + unionSelect.setIsOpen(true); + } + if (unionSelect.getEnable() == null) { + unionSelect.setEnable(true); + } + } + + dao().insertOrUpdate(lineUnionSelects); + List newIds = Arrays.stream(lineUnionSelects) + .map(TheRapyRecuperationLineUnionSelect::getId) + .filter(StrUtil::isNotBlank) + .collect(Collectors.toList()); + List deleteIds = oldUnionSelects.stream() + .map(TheRapyRecuperationLineUnionSelect::getId) + .filter(v -> !newIds.contains(v)) + .collect(Collectors.toList()); + if (Lang.isNotEmpty(deleteIds)) { + long enrollCount = dao().count(TheRapyRecuperationEnroll.class, Cnd.where("takePartInLineId", "in", deleteIds)); + if (enrollCount > 0) { + throw Lang.makeThrow("已存在报名记录的出行时间段不能删除"); + } + clear(Cnd.where("id", "in", deleteIds)); + } + } + + /** + * 管理员维护出行时间段时校验关键字段,避免保存不完整时间或无法联系的旅行社信息。 + */ + private void validateAdminLineTime(TheRapyRecuperationLineUnionSelect unionSelect) { + if (unionSelect.getSignUpStartTime() == null) { + throw Lang.makeThrow("请选择报名开始时间"); + } + if (unionSelect.getSignUpEndTime() == null) { + throw Lang.makeThrow("请选择报名结束时间"); + } + if (DateUtil.compare(unionSelect.getSignUpEndTime(), unionSelect.getSignUpStartTime()) <= 0) { + throw Lang.makeThrow("报名结束时间必须大于报名开始时间"); + } + if (unionSelect.getChangeEndTime() == null) { + throw Lang.makeThrow("请选择变更截至时间"); + } + if (unionSelect.getPlayStartTime() == null) { + throw Lang.makeThrow("请选择出行开始时间"); + } + if (unionSelect.getPlayEndTime() == null) { + throw Lang.makeThrow("请选择出行结束时间"); + } + if (DateUtil.compare(unionSelect.getPlayEndTime(), unionSelect.getPlayStartTime()) <= 0) { + throw Lang.makeThrow("出行结束时间必须大于出行开始时间"); + } + if (StrUtil.isBlank(unionSelect.getTravelAgencyId())) { + throw Lang.makeThrow("请选择旅行社"); + } + if (StrUtil.isBlank(unionSelect.getContact())) { + throw Lang.makeThrow("请填写联系人"); + } + if (StrUtil.isBlank(unionSelect.getContactPhone())) { + throw Lang.makeThrow("请填写联系电话"); + } + if (StrUtil.isBlank(unionSelect.getPrincipal())) { + throw Lang.makeThrow("请填写负责人"); + } + if (StrUtil.isBlank(unionSelect.getPrincipalContact())) { + throw Lang.makeThrow("请填写负责人联系方式"); + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationTravelAgencyServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationTravelAgencyServiceImpl.java new file mode 100644 index 0000000..dc38dd5 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/TheRapyRecuperationTravelAgencyServiceImpl.java @@ -0,0 +1,124 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl; + +import com.budwk.app.base.page.Pagination; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.base.param.PageForm; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationTravelAgency; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.TheRapyRecuperationTravelAgencyService; +import org.nutz.dao.Chain; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.IocBean; + +import java.util.List; + +/** + * @FileName com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.TheRapyRecuperationTravelAgencyServiceImpl + * @Description: 疗休养旅行社 + * @Author zxc + * @Date 2022/5/31:14:46 + * @Version V1.0 + **/ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationTravelAgencyServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationTravelAgencyService { + + public TheRapyRecuperationTravelAgencyServiceImpl(Dao dao) { + super(dao); + } + + /** + * 删除旅行社 + * + * @param travelAgencyId 旅行社 ID + */ + @Override + public void deleteTravelAgency(String travelAgencyId) { + delete(travelAgencyId); + } + + /** + * 添加旅行社 + * + * @param travelAgency 旅行社 + */ + @Override + public void addTravelAgency(TheRapyRecuperationTravelAgency travelAgency) { + insert(travelAgency); + } + + /** + * 编辑旅行社 + * + * @param travelAgency 旅行社 + */ + @Override + public void editTravelAgency(TheRapyRecuperationTravelAgency travelAgency) { + update(travelAgency); + } + + /** + * 开启或关闭旅行社 + * + * @param travelAgencyId 旅行社id + */ + @Override + public void openTravelAgency(String travelAgencyId) { + //位运算 取反 + update(Chain.makeSpecial("isDisabled", "isDisabled ^ 1"), Cnd.where("id", "=", travelAgencyId)); + } + + /** + * 页面数据 + * + * @param pageForm 分页参数 + * @param cnd cnd + * @return {@link Pagination} + */ + @Override + public Pagination pageData(PageForm pageForm, Cnd cnd) { + Sql sql = Sqls.create(""" + select + *, + files as fileId + from + staff_therapy_travel_agency $condition + """); + sql.setCondition(cnd); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } + + /** + * 查询旅行社 + * + * @param cnd cnd + * @return {@link List}<{@link TheRapyRecuperationTravelAgency}> + */ + @Override + public List selectAllTravelAgencyByYear(Cnd cnd) { + return dao().query(TheRapyRecuperationTravelAgency.class, cnd); + } + + @Override + public Pagination selectAgencyUser(PageForm pageForm, String id) { + Sql sql = Sqls.create(""" + SELECT + agency.travelAgencyName, + enroll.id, + enroll.loginName, + enroll.userName, + enroll.unionName, + enroll.unitName, + ( SELECT COUNT( 1 ) FROM staff_therapy_enroll_companion WHERE trreId = enroll.id AND relation = '亲属' ) isFamily + FROM + `staff_therapy_enroll` enroll + LEFT JOIN staff_therapy_travel_agency agency ON agency.id = enroll.takePartInTravelAgencyId + WHERE + enroll.takePartInTravelAgencyId = @takePartInTravelAgencyId + and enroll.selfUnionId = @unionId + """).setParam("takePartInTravelAgencyId", id).setParam("unionId", TherapyContext.getUnionId()); + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java new file mode 100644 index 0000000..c33b673 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/service/impl/baseManage/TheRapyRecuperationBaseManagerServiceImpl.java @@ -0,0 +1,68 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.impl.baseManage; + +import cn.hutool.core.date.DateUtil; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyServiceImpl; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support.TherapyContext; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.model.TheRapyRecuperationConfig; +import com.budwk.app.zhgh.staffbenefit.therapyRecuperation.service.baseManage.TheRapyRecuperationBaseManagerService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.dao.Sqls; +import org.nutz.dao.sql.Sql; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.util.NutMap; + +/** + * @Author JyuHsin + * @Date 2023/6/7 + * @Description + */ +@IocBean(args = {"refer:dao"}) +public class TheRapyRecuperationBaseManagerServiceImpl extends TherapyServiceImpl implements TheRapyRecuperationBaseManagerService { + + public TheRapyRecuperationBaseManagerServiceImpl(Dao dao) { + super(dao); + } + + @Override + public NutMap selectBaseAllInfo(String id) { + Sql sql = Sqls.create(""" + select + b.*, + l.lotName, + (select COUNT(1) FROM staff_therapy_enroll en WHERE isNormal=true AND en.loginName=@loginname and YEAR(en.signingUptime)=@year ) isNormal, + (select COUNT(1) FROM staff_therapy_enroll en WHERE isNormal=false AND en.loginName=@loginname and YEAR(en.signingUptime)=@year) isNormalFalse + from + staff_therapy_base_management b + left join staff_therapy_lot l on l.id = b.lotId + $condition + """); + sql.setParam("loginname", TherapyContext.getPrincipalProperty("loginname")); + sql.setParam("year", DateUtil.thisYear()); + Cnd cnd = Cnd.NEW(); + cnd.and("b.id", "=", id); + sql.setCondition(cnd); + sql.setCallback(Sqls.callback.map()); + dao().execute(sql); + NutMap nutMap = (NutMap) sql.getResult(); + useConfigSignUpTime(nutMap); + return nutMap; + } + + /** + * 手机端目的地详情报名时间统一使用基础设置中的报名时间。 + * + * @param nutMap 目的地详情返回数据 + */ + private void useConfigSignUpTime(NutMap nutMap) { + if (nutMap == null) { + return; + } + TheRapyRecuperationConfig config = dao().fetch(TheRapyRecuperationConfig.class); + if (config == null) { + return; + } + nutMap.setv("signUpStartTime", config.getSignUpStartTime()); + nutMap.setv("signUpEndTime", config.getSignUpEndTime()); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/LegacyBaseModel.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/LegacyBaseModel.java new file mode 100644 index 0000000..85d6492 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/LegacyBaseModel.java @@ -0,0 +1,20 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.base.model.BaseModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; + +@Data +@EqualsAndHashCode(callSuper = true) +public abstract class LegacyBaseModel extends BaseModel { + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + @PrevInsert(els = @EL("$me.createdByUid()")) + private String opBy; + + @Column + @ColDefine(type = ColType.VARCHAR, width = 32) + private String opAt; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/PageUtil.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/PageUtil.java new file mode 100644 index 0000000..12adb41 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/PageUtil.java @@ -0,0 +1,7 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +public class PageUtil { + public static String getOrder(String value) { + return "descending".equals(value) ? "desc" : "asc"; + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/SelectEnum.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/SelectEnum.java new file mode 100644 index 0000000..a83392f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/SelectEnum.java @@ -0,0 +1,7 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface SelectEnum {} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAudit.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAudit.java new file mode 100644 index 0000000..e27041d --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAudit.java @@ -0,0 +1,29 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.nutz.dao.entity.annotation.*; +import org.nutz.dao.interceptor.annotation.PrevInsert; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@Table("staff_therapy_audit") +public class TherapyAudit extends LegacyBaseModel { + @Name + @PrevInsert(uu32 = true) + private String id; + @Column + private String auditor; + @Column + private Boolean auditPass; + @Column + private Date auditTime; + @Column + @ColDefine(type = ColType.TEXT) + private String auditOpinion; + @Column + private String username; + @Column + private String loginname; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAuditState.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAuditState.java new file mode 100644 index 0000000..4da1146 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyAuditState.java @@ -0,0 +1,15 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +@Data +@Table("staff_therapy_audit_state") +public class TherapyAuditState { + @Id(auto = false) + private Integer stateId; + @Column + private String stateName; + @Column + private String stateColor; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyContext.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyContext.java new file mode 100644 index 0000000..cca6446 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyContext.java @@ -0,0 +1,95 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import cn.dev33.satoken.stp.StpUtil; +import com.budwk.app.web.commons.auth.utils.SecurityUtil; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.lang.Strings; +import org.nutz.mvc.Mvcs; + +import java.util.Arrays; +import java.util.Collection; + +@IocBean +public class TherapyContext { + public static String getUserId() { + return SecurityUtil.getUserId(); + } + + public static String getPlatformUid() { + return getUserId(); + } + + public static String getUnionId() { + String unionId = SecurityUtil.getUnionId(); + if (Strings.isNotBlank(unionId)) return unionId; + TherapyUser user = Mvcs.getIoc().get(Dao.class).fetch(TherapyUser.class, getUserId()); + return user == null ? "" : Strings.sNull(user.getUnionid()); + } + + public static boolean hasRole(String role) { + if (StpUtil.hasRole(role)) return true; + switch (role) { + case "sysadmin": return StpUtil.hasRole("SYSADMIN") || StpUtil.hasRole("superadmin"); + case "A06": return StpUtil.hasRole("SCHOOL_UNION_ADMIN") || StpUtil.hasRole("SCHOOL_UNION_WELFARE_ADMIN"); + case "H03": return StpUtil.hasRole("BRANCH_UNION_CHAIRMAN"); + case "H04": return StpUtil.hasRole("BRANCH_UNION_ADMIN") || StpUtil.hasRole("BRANCH_UNION_CHAIRMAN"); + case "H06": return StpUtil.hasRole("SCHOOL_UNION_WELFARE_ADMIN"); + case "SchoolUnionMemberAdmin": return StpUtil.hasRole("SCHOOL_UNION_MEMBER_ADMIN"); + default: return false; + } + } + + public static boolean hasAnyRoles(String roles) { + return hasAnyRoles(Arrays.asList(roles.split(","))); + } + + public static boolean hasAnyRoles(String[] roles) { + return hasAnyRoles(Arrays.asList(roles)); + } + + public static boolean hasAnyRoles(Collection roles) { + return roles.stream().map(String::trim).anyMatch(TherapyContext::hasRole); + } + + public static boolean isNotBlank(String... values) { + return Arrays.stream(values).allMatch(Strings::isNotBlank); + } + + public static String getRoleCodesJson() { + java.util.List roles = new java.util.ArrayList<>(StpUtil.getRoleList()); + for (String role : Arrays.asList("sysadmin", "A06", "H03", "H04", "H06", "SchoolUnionMemberAdmin")) { + if (hasRole(role) && !roles.contains(role)) roles.add(role); + } + return org.nutz.json.Json.toJson(roles, org.nutz.json.JsonFormat.compact()); + } + + public static TherapyUser getUser() { + Dao dao = Mvcs.getIoc().get(Dao.class); + TherapyUser user = dao.fetch(TherapyUser.class, getUserId()); + return user == null ? null : dao.fetchLinks(user, "^(unit|union)$"); + } + + public static TherapyUser getPrincipal() { + return getUser(); + } + + public static Object getPrincipalProperty(String property) { + switch (property) { + case "id": return getUserId(); + case "loginname": return SecurityUtil.getUserLoginname(); + case "username": return SecurityUtil.getUserUsername(); + case "unionid": return getUnionId(); + default: + TherapyUser user = getUser(); + if (user == null) return null; + switch (property) { + case "unit": return user.getUnit(); + case "union": return user.getUnion(); + case "mobile": return user.getMobile(); + case "idcard": return user.getIdcard(); + default: throw new IllegalArgumentException(property); + } + } + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDataService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDataService.java new file mode 100644 index 0000000..956fc5a --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDataService.java @@ -0,0 +1,11 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.IocBean; + +@IocBean(name = "staffTherapyDataService", args = {"refer:dao"}) +public class TherapyDataService extends TherapyServiceImpl { + public TherapyDataService(Dao dao) { + super(dao); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDownload.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDownload.java new file mode 100644 index 0000000..a493c86 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyDownload.java @@ -0,0 +1,13 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import javax.servlet.http.HttpServletResponse; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +public class TherapyDownload { + public static void excelResponse(HttpServletResponse response, String name) { + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setHeader("Content-Disposition", "attachment;filename*=UTF-8''" + + URLEncoder.encode(name, StandardCharsets.UTF_8).replace("+", "%20")); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyEmail.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyEmail.java new file mode 100644 index 0000000..34f0f43 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyEmail.java @@ -0,0 +1,117 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.web.commons.base.Globals; +import com.budwk.app.sys.models.Sys_config; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.ioc.impl.PropertiesProxy; +import java.io.*; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Base64; +import java.util.UUID; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +@IocBean +public class TherapyEmail { + @Inject + private PropertiesProxy conf; + @Inject + private Dao dao; + + public void send(String email, String content, boolean html, File... files) { + String host = setting("host"); + String from = setting("from"); + String user = setting("user"); + String password = setting("password"); + if (host == null || from == null || user == null || password == null) { + throw new IllegalStateException("职工疗休养邮件发送配置不完整"); + } + String portSetting = setting("port"); + int port = portSetting == null ? 465 : Integer.parseInt(portSetting); + String[] recipients = email.split("[,;]"); + checkAddress(from); + for (String recipient : recipients) checkAddress(recipient.trim()); + // Use the JDK TLS client so the migrated mail feature needs no additional dependencies. + try (Socket transport = new Socket()) { + transport.connect(new InetSocketAddress(host, port), 30000); + try (SSLSocket socket = (SSLSocket) ((SSLSocketFactory) SSLSocketFactory.getDefault()).createSocket(transport, host, port, true)) { + socket.setSoTimeout(30000); + javax.net.ssl.SSLParameters parameters = socket.getSSLParameters(); + parameters.setEndpointIdentificationAlgorithm("HTTPS"); + socket.setSSLParameters(parameters); + socket.startHandshake(); + BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.US_ASCII)); + BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.US_ASCII)); + expect(in, 220); + command(out, in, "EHLO localhost", 250); + command(out, in, "AUTH LOGIN", 334); + command(out, in, encoded(user), 334); + command(out, in, encoded(password), 235); + command(out, in, "MAIL FROM:<" + from + ">", 250); + for (String recipient : recipients) command(out, in, "RCPT TO:<" + recipient.trim() + ">", 250, 251); + command(out, in, "DATA", 354); + String boundary = "therapy_" + UUID.randomUUID().toString().replace("-", ""); + out.write("From: " + from + "\r\nTo: " + String.join(",", recipients) + "\r\n"); + out.write("Subject: =?UTF-8?B?" + encoded(Globals.AppName + "疗休养管理系统") + "?=\r\n"); + out.write("MIME-Version: 1.0\r\nContent-Type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n"); + out.write("--" + boundary + "\r\nContent-Type: text/" + (html ? "html" : "plain") + "; charset=UTF-8\r\n"); + out.write("Content-Transfer-Encoding: base64\r\n\r\n"); + writeBody(out, content.getBytes(StandardCharsets.UTF_8)); + for (File file : files) { + out.write("--" + boundary + "\r\nContent-Type: application/octet-stream\r\n"); + out.write("Content-Disposition: attachment; filename=\"=?UTF-8?B?" + encoded(file.getName()) + "?=\"\r\n"); + out.write("Content-Transfer-Encoding: base64\r\n\r\n"); + writeBody(out, Files.readAllBytes(file.toPath())); + } + out.write("--" + boundary + "--\r\n.\r\n"); + out.flush(); + expect(in, 250); + command(out, in, "QUIT", 221); + } + } catch (IOException e) { + throw new IllegalStateException("疗休养名单邮件发送失败", e); + } + } + + private String setting(String name) { + String key = "staffTherapy.mail." + name; + String value = conf.get(key); + if (value != null && !value.isBlank()) return value; + Sys_config config = dao.fetch(Sys_config.class, key); + return config == null || config.getConfigValue() == null || config.getConfigValue().isBlank() ? null : config.getConfigValue(); + } + + private static void checkAddress(String address) { + if (!address.matches("[^\\s<>@]+@[^\\s<>@]+")) throw new IllegalArgumentException("邮件地址格式错误"); + } + + private static String encoded(String text) { + return Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8)); + } + + private static void writeBody(BufferedWriter out, byte[] bytes) throws IOException { + out.write(Base64.getMimeEncoder(76, new byte[]{13, 10}).encodeToString(bytes)); + out.write("\r\n"); + } + + private static void command(BufferedWriter out, BufferedReader in, String value, int... codes) throws IOException { + out.write(value + "\r\n"); + out.flush(); + expect(in, codes); + } + + private static void expect(BufferedReader in, int... codes) throws IOException { + String response; + do { + response = in.readLine(); + if (response == null || response.length() < 3) throw new IOException("SMTP connection closed"); + } while (response.length() > 3 && response.charAt(3) == '-'); + for (int code : codes) if (response.startsWith(String.valueOf(code))) return; + throw new IOException("SMTP request rejected"); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyMessage.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyMessage.java new file mode 100644 index 0000000..2c28eec --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyMessage.java @@ -0,0 +1,28 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.sys.models.Sys_user; +import com.budwk.app.zhgh.dayofficework.message.service.GlobalMessageSendService; +import org.nutz.dao.Cnd; +import org.nutz.dao.Dao; +import org.nutz.ioc.loader.annotation.Inject; +import org.nutz.ioc.loader.annotation.IocBean; +import java.util.*; + +@IocBean +public class TherapyMessage { + public enum sendMode { normal } + @Inject + private Dao dao; + @Inject + private GlobalMessageSendService globalMessageSendService; + + public void sendMsg(String content, List receivers, String title, String mode, String sendMode) { + Set ids = new LinkedHashSet<>(); + for (Map receiver : receivers) { + String loginname = String.valueOf(receiver.get("userId")); + Sys_user user = dao.fetch(Sys_user.class, Cnd.where("loginname", "=", loginname)); + if (user != null) ids.add(user.getId()); + } + if (!ids.isEmpty()) globalMessageSendService.sendMessage(title, content, new ArrayList<>(ids)); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyReturnConfiguration.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyReturnConfiguration.java new file mode 100644 index 0000000..57cae7f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyReturnConfiguration.java @@ -0,0 +1,43 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.base.result.Result; +import org.nutz.aop.MethodInterceptor; +import org.nutz.ioc.Ioc; +import org.nutz.ioc.aop.config.AopConfigration; +import org.nutz.ioc.aop.config.InterceptorPair; +import org.nutz.ioc.loader.annotation.IocBean; +import org.nutz.log.Log; +import org.nutz.log.Logs; + +import java.util.Collections; +import java.util.List; + +@IocBean(name = "$aop_staffTherapyReturn") +public class TherapyReturnConfiguration implements AopConfigration { + private static final Log log = Logs.get(); + + @Override + public List getInterceptorPairList(Ioc ioc, Class type) { + if (!type.getName().startsWith("com.budwk.app.zhgh.staffbenefit.therapyRecuperation.controller.")) { + return Collections.emptyList(); + } + MethodInterceptor interceptor = chain -> { + cn.dev33.satoken.stp.StpUtil.checkLogin(); + ViReturn annotation = chain.getCallingMethod().getAnnotation(ViReturn.class); + if (annotation == null) { + chain.doChain(); + return; + } + try { + chain.doChain(); + Object value = chain.getReturn(); + chain.setReturnValue(value instanceof Result ? value : Result.success(annotation.successMsg(), value)); + } catch (Exception e) { + log.error(e); + chain.setReturnValue(Result.error(e.getMessage() == null ? annotation.errorMsg() : e.getMessage())); + } + }; + return Collections.singletonList(new InterceptorPair(interceptor, + method -> method.isAnnotationPresent(org.nutz.mvc.annotation.At.class))); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyService.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyService.java new file mode 100644 index 0000000..ad490c1 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyService.java @@ -0,0 +1,10 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.base.service.BaseService; +import org.nutz.dao.sql.Sql; +import org.nutz.lang.util.NutMap; + +public interface TherapyService extends BaseService { + NutMap fetch(Sql sql); + com.budwk.app.base.page.Pagination list(com.budwk.app.base.param.PageForm pageForm, Sql sql); +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyServiceImpl.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyServiceImpl.java new file mode 100644 index 0000000..43e3326 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyServiceImpl.java @@ -0,0 +1,22 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.base.service.impl.BaseServiceImpl; +import org.nutz.dao.Dao; +import org.nutz.dao.sql.Sql; +import org.nutz.lang.util.NutMap; + +public class TherapyServiceImpl extends BaseServiceImpl implements TherapyService { + public TherapyServiceImpl(Dao dao) { + super(dao); + } + + @Override + public NutMap fetch(Sql sql) { + return fetchMap(sql); + } + + @Override + public com.budwk.app.base.page.Pagination list(com.budwk.app.base.param.PageForm pageForm, Sql sql) { + return listPageMap(pageForm.getPageNumber(), pageForm.getPageSize(), sql); + } +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUnion.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUnion.java new file mode 100644 index 0000000..dd6faf5 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUnion.java @@ -0,0 +1,18 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +@Data +@View("staff_therapy_union") +public class TherapyUnion { + @Name + @Column + private String id; + @Column + private String unionname; + @Column + private String name; + @Column + private String unioncode; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUser.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUser.java new file mode 100644 index 0000000..8cf786f --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/TherapyUser.java @@ -0,0 +1,41 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import com.budwk.app.sys.models.Sys_unit; +import lombok.Data; +import org.nutz.dao.entity.annotation.*; + +@Data +@View("staff_therapy_user") +public class TherapyUser { + @Name + @Column + private String id; + @Column + private String loginname; + @Column + private String username; + @Column + private String sex; + @Column + private String idcard; + @Column + private String mobile; + @Column + private String schoolTime; + @Column + private String unitid; + @Column + private String unitname; + @Column + private String unionid; + @Column + private String unionname; + @Column + private String personType; + @Column + private String userState; + @One(field = "unitid") + private Sys_unit unit; + @One(field = "unionid") + private TherapyUnion union; +} diff --git a/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/ViReturn.java b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/ViReturn.java new file mode 100644 index 0000000..e2230c8 --- /dev/null +++ b/src/main/java/com/budwk/app/zhgh/staffbenefit/therapyRecuperation/support/ViReturn.java @@ -0,0 +1,10 @@ +package com.budwk.app.zhgh.staffbenefit.therapyRecuperation.support; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface ViReturn { + String successMsg() default "操作成功"; + String errorMsg() default "操作失败"; +} diff --git a/src/main/resources/db/v4_from_v3/init_staff_therapy_recuperation.sql b/src/main/resources/db/v4_from_v3/init_staff_therapy_recuperation.sql new file mode 100644 index 0000000..99a7585 --- /dev/null +++ b/src/main/resources/db/v4_from_v3/init_staff_therapy_recuperation.sql @@ -0,0 +1,687 @@ +-- v4 职工福利 / 职工疗休养独立子模块初始化脚本(MySQL 8)。 +-- 在 v4 目标数据库中执行;表结构依据 therapyRecuperation 模块实体定义。 +-- v3 the_rapy_recuperation_* 对应本模块 staff_therapy_*,不覆盖 v4 其他疗休养表。 +-- 仅新增表、视图、默认配置、菜单及角色权限关联,不迁移 v3 历史业务数据。 +-- 已存在的表、视图、配置和菜单保留原值;脚本不修订已有表结构。 +-- 依赖 v4 已有 vw_user、sys_union、sys_unit、sys_config、sys_module、sys_menu、sys_role、sys_role_menu。 +-- DDL 存在 MySQL 隐式提交;后续初始化记录使用单独事务。 +SET NAMES utf8mb4; + +CREATE TABLE IF NOT EXISTS `staff_therapy_base_management` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `year` int NULL DEFAULT NULL COMMENT '年度', + `sortNumber` varchar(50) NULL DEFAULT NULL COMMENT '排序编号', + `baseName` varchar(50) NULL DEFAULT NULL COMMENT '基地名称', + `travelAgencyId` varchar(32) NULL DEFAULT NULL COMMENT '旅行社Id', + `regionalNature` varchar(10) NULL DEFAULT NULL COMMENT '区域', + `lotId` varchar(32) NULL DEFAULT NULL COMMENT '标段Id', + `content` text NULL COMMENT '疗休养详情', + `isDisabled` tinyint(1) NULL DEFAULT NULL COMMENT '是否禁用', + `createUnionId` varchar(32) NULL DEFAULT NULL COMMENT '哪个分工会创建的', + `signUpStartTime` datetime NULL DEFAULT NULL COMMENT '报名开始时间', + `signUpEndTime` datetime NULL DEFAULT NULL COMMENT '报名截至时间', + `changeEndTime` datetime NULL DEFAULT NULL COMMENT '变更截至时间', + `activityStartTime` datetime NULL DEFAULT NULL COMMENT '活动开始时间', + `activityEndTime` datetime NULL DEFAULT NULL COMMENT '活动结束时间', + `estimatedCost` varchar(50) NULL DEFAULT NULL COMMENT '预计费用', + `files` json NULL COMMENT '缩略图', + `createMode` int NULL DEFAULT NULL COMMENT '创建模式(1.校工会 2.分工会)', + `baseContactPerson` varchar(50) NULL DEFAULT NULL COMMENT '基地联系人', + `baseContactNumber` varchar(50) NULL DEFAULT NULL COMMENT '基地联系人电话', + `opBy` varchar(50) NULL DEFAULT NULL COMMENT '操作人', + `opAt` varchar(50) NULL DEFAULT NULL COMMENT '操作时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养目的地'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_cluster` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `lineId` varchar(32) NULL DEFAULT NULL COMMENT '线路id', + `clusterName` varchar(50) NULL DEFAULT NULL COMMENT '团名', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养组团'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_cluster_member` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `lineId` varchar(32) NULL DEFAULT NULL COMMENT '线路id', + `clusterId` varchar(32) NULL DEFAULT NULL COMMENT '团Id', + `loginName` varchar(20) NULL DEFAULT NULL COMMENT '工号', + `userName` varchar(20) NULL DEFAULT NULL COMMENT '姓名', + `sex` char(1) NULL DEFAULT NULL COMMENT '性别', + `unionName` varchar(50) NULL DEFAULT NULL COMMENT '工会', + `isLeader` tinyint(1) NULL DEFAULT NULL COMMENT '是否领队', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养组团成员'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_config` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `configName` varchar(30) NULL DEFAULT NULL COMMENT '配置名称', + `activityGroupId` bigint NULL DEFAULT NULL COMMENT '参加人员范围', + `signUpStartTime` datetime NULL DEFAULT NULL COMMENT '报名开始时间', + `signUpEndTime` datetime NULL DEFAULT NULL COMMENT '报名结束时间', + `lineSelectStartTime` datetime NULL DEFAULT NULL COMMENT '选择线路开始时间', + `lineSelectEndTime` datetime NULL DEFAULT NULL COMMENT '选择线路结束时间', + `outsideQuota` int NULL DEFAULT NULL COMMENT '省外名额分配', + `outsideQuotaProportion` decimal(3,2) NULL DEFAULT NULL COMMENT '省外名额分配比例', + `outsideNumber` int NULL DEFAULT NULL COMMENT '省外几年去一次', + `travelFrequency` int NULL DEFAULT NULL COMMENT '每年旅行频率', + `groupNumber` int NULL DEFAULT NULL COMMENT '组团人数', + `modifyDays` int NULL DEFAULT NULL COMMENT '不可取消修改天数', + `modifyNumber` int NULL DEFAULT NULL COMMENT '可以修改几次', + `isSnLine` tinyint(1) NULL DEFAULT '0' COMMENT '省内线路是否审核', + `isSwLine` tinyint(1) NULL DEFAULT '0' COMMENT '省外线路是否审核', + `travelAudit` tinyint(1) NULL DEFAULT '0' COMMENT '旅行社是否审核', + `modifyBd` json NULL COMMENT '标段', + `unionLineNumberConfigs` json NULL COMMENT '分工会线路数量配置', + `allLineSignUpNumber` int NULL DEFAULT NULL COMMENT '全批次最多教职工报名人数', + `notice` longtext NULL COMMENT '疗休养服务须知', + `provinceStartYear` int NULL DEFAULT NULL COMMENT '省内起始年份', + `bedInfo` tinyint(1) NULL DEFAULT '0' COMMENT '床位信息', + `familyInfo` int NULL DEFAULT '0' COMMENT '家属信息', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养配置'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_enroll` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `loginName` varchar(32) NULL DEFAULT NULL COMMENT '工号', + `userName` varchar(32) NULL DEFAULT NULL COMMENT '姓名', + `sex` varchar(1) NULL DEFAULT NULL COMMENT '性别', + `unitName` varchar(50) NULL DEFAULT NULL COMMENT '本人单位', + `unionName` varchar(50) NULL DEFAULT NULL COMMENT '本人分工会', + `selfUnitId` varchar(32) NULL DEFAULT NULL COMMENT '本人单位', + `selfUnionId` varchar(32) NULL DEFAULT NULL COMMENT '本人分工会Id', + `takePartInUnionId` varchar(32) NULL DEFAULT NULL COMMENT '参加的分工会', + `takePartInLineId` varchar(32) NULL DEFAULT NULL COMMENT '参加线路', + `takePartInTravelAgencyId` varchar(32) NULL DEFAULT NULL COMMENT '参加旅行社', + `takePartInBaseManagementId` varchar(32) NULL DEFAULT NULL COMMENT '参加酒店', + `signingUptime` datetime NULL DEFAULT NULL COMMENT '报名时间', + `takePartInTime` date NULL DEFAULT NULL COMMENT '参加时间', + `isTakePartIn` tinyint(1) NULL DEFAULT NULL COMMENT '是否参加', + `stateId` int NULL DEFAULT NULL COMMENT '审核状态', + `selfUnionAuditId` varchar(32) NULL DEFAULT NULL COMMENT '本人分工会审核Id', + `bedInfoId` varchar(32) NULL DEFAULT NULL COMMENT '床位信息id', + `joinLineUnionAuditId` varchar(32) NULL DEFAULT NULL COMMENT '参加的线路分工会审核Id', + `idCard` varchar(18) NULL DEFAULT NULL COMMENT '身份证号', + `mobile` varchar(20) NULL DEFAULT NULL COMMENT '手机号', + `isNormal` tinyint(1) NULL DEFAULT NULL COMMENT '是否正常(true正常 false该报名记录已被管理员废弃)', + `evaluationForTravelAgency` varchar(128) NULL DEFAULT NULL COMMENT '对旅行社的评价(几星)', + `evaluationForLine` varchar(128) NULL DEFAULT NULL COMMENT '对线路的评价(几星)', + `evaluationForJourney` varchar(128) NULL DEFAULT NULL COMMENT '对旅途的评价(几星)', + `feedbackContent` varchar(100) NULL DEFAULT NULL COMMENT '反馈内容', + `lotId` varchar(32) NULL DEFAULT NULL COMMENT '标段时间', + `schoolUnionAuditId` varchar(32) NULL DEFAULT NULL COMMENT '校工会审核Id', + `familyNumber` int NULL DEFAULT NULL COMMENT '家属数量', + `isReimbursement` tinyint(1) NULL DEFAULT NULL COMMENT '是否报销', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养报名登记表'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_enroll_bed` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `bedType` varchar(10) NULL DEFAULT NULL COMMENT '床型', + `bedNum` int NULL DEFAULT NULL COMMENT '床位数', + `isSleepTogether` tinyint(1) NULL DEFAULT NULL COMMENT '一起睡吗 搞基', + `otherSleepUser` varchar(128) NULL DEFAULT NULL COMMENT '意向拼房人', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养报名床位'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_enroll_change_record` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `enrollId` varchar(32) NULL DEFAULT NULL COMMENT '变更记录id', + `changeTime` datetime NULL DEFAULT NULL COMMENT '变更时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养报名变更记录'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_enroll_companion` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `trreId` varchar(32) NULL DEFAULT NULL COMMENT '报名记录表Id', + `loginName` varchar(32) NULL DEFAULT NULL COMMENT '工号', + `userName` varchar(32) NULL DEFAULT NULL COMMENT '姓名', + `sex` char(1) NULL DEFAULT NULL COMMENT '性别', + `age` int NULL DEFAULT NULL COMMENT '年龄', + `relation` varchar(10) NULL DEFAULT NULL COMMENT '关系', + `idCard` varchar(18) NULL DEFAULT NULL COMMENT '身份证号', + `mobile` varchar(18) NULL DEFAULT NULL COMMENT '手机号', + `bedInfoId` varchar(32) NULL DEFAULT NULL COMMENT '床位信息id', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养随行人员'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_line` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `serialNumber` int NULL DEFAULT NULL COMMENT '编号', + `lineName` varchar(50) NULL DEFAULT NULL COMMENT '线路名称', + `travelAgencyId` varchar(32) NULL DEFAULT NULL COMMENT '旅行社Id', + `regionalNature` varchar(10) NULL DEFAULT NULL COMMENT '区域性质', + `playNumberOfDays` int NULL DEFAULT NULL COMMENT '游玩天数', + `content` text NULL COMMENT '疗休养内容', + `minimumGroupSize` int NULL DEFAULT NULL COMMENT '最少参与教工', + `year` int NULL DEFAULT NULL COMMENT '年度', + `isDisabled` tinyint(1) NULL DEFAULT NULL COMMENT '是否禁用', + `createUnionId` varchar(32) NULL DEFAULT NULL COMMENT '哪个分工会创建的', + `signUpStartTime` datetime NULL DEFAULT NULL COMMENT '报名开始时间', + `signUpEndTime` datetime NULL DEFAULT NULL COMMENT '报名截至时间', + `changeEndTime` datetime NULL DEFAULT NULL COMMENT '变更截至时间', + `playStartTime` datetime NULL DEFAULT NULL COMMENT '游玩开始时间', + `playEndTime` datetime NULL DEFAULT NULL COMMENT '游玩结束时间', + `trafficTools` varchar(50) NULL DEFAULT NULL COMMENT '交通工具', + `estimatedCost` varchar(50) NULL DEFAULT NULL COMMENT '预计费用', + `estimatedFamilyNumbers` int NULL DEFAULT NULL COMMENT '成团人数包括家属', + `files` varchar(30) NULL DEFAULT NULL COMMENT '缩略图', + `signUpMode` int NULL DEFAULT NULL COMMENT '报名模式(1.分工会 2.自由)', + `createMode` int NULL DEFAULT NULL COMMENT '创建模式(1.分工会 2.校工会)', + `lotId` varchar(128) NULL DEFAULT NULL COMMENT '标段', + `lineContact` varchar(128) NULL DEFAULT NULL COMMENT '联系人', + `lineContactPhone` varchar(128) NULL DEFAULT NULL COMMENT '联系电话', + `isFamilySignUp` tinyint(1) NULL DEFAULT NULL COMMENT '是否家属报名', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养线路'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_line_union_select` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `unionId` varchar(32) NULL DEFAULT NULL COMMENT '分工会id', + `lineId` varchar(32) NULL DEFAULT NULL COMMENT '线路id', + `selectTime` datetime NULL DEFAULT NULL COMMENT '选择时间', + `selectUserId` varchar(32) NULL DEFAULT NULL COMMENT '选择用户', + `signUpStartTime` datetime NULL DEFAULT NULL COMMENT '报名开始时间', + `signUpEndTime` datetime NULL DEFAULT NULL COMMENT '报名截至时间', + `changeEndTime` datetime NULL DEFAULT NULL COMMENT '变更截至时间', + `adjustSignUpEndTime` datetime NULL DEFAULT NULL COMMENT '调剂报名截止时间', + `playStartTime` datetime NULL DEFAULT NULL COMMENT '游玩开始时间', + `playEndTime` datetime NULL DEFAULT NULL COMMENT '游玩结束时间', + `contact` varchar(128) NULL DEFAULT NULL COMMENT '联系人', + `contactPhone` varchar(128) NULL DEFAULT NULL COMMENT '联系电话', + `principal` varchar(128) NULL DEFAULT NULL COMMENT '负责人', + `principalContact` varchar(128) NULL DEFAULT NULL COMMENT '联系方式', + `isOpen` tinyint(1) NULL DEFAULT NULL COMMENT '是否公开', + `minimumGroupSize` int NULL DEFAULT NULL COMMENT '最少参与教工', + `trafficTools` varchar(50) NULL DEFAULT NULL COMMENT '交通工具', + `estimatedCost` varchar(50) NULL DEFAULT NULL COMMENT '预计费用', + `estimatedFamilyNumbers` int NULL DEFAULT NULL COMMENT '成团人数包括家属', + `maxPeopleNumber` int NULL DEFAULT NULL COMMENT '最多人数', + `signUpMode` int NULL DEFAULT NULL COMMENT '报名模式、组织形式(1.分工会 2.校工会)', + `enable` tinyint(1) NULL DEFAULT NULL COMMENT '是否启用', + `travelAgencyId` varchar(32) NULL DEFAULT NULL COMMENT '旅行社id', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养工会选线'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_lot` ( + `id` varchar(32) NOT NULL COMMENT 'id', + `lotName` varchar(10) NULL DEFAULT NULL COMMENT '标段', + `lotValue` varchar(10) NULL DEFAULT NULL COMMENT '标段值', + `activityCost` varchar(10) NULL DEFAULT NULL COMMENT '费用', + `configId` varchar(32) NULL DEFAULT NULL COMMENT '配置ID', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养标段'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_travel_agency` ( + `id` varchar(128) NOT NULL COMMENT 'id', + `serialNumber` varchar(50) NULL DEFAULT NULL COMMENT '旅行社编号', + `travelAgencyName` varchar(50) NULL DEFAULT NULL COMMENT '旅行社名称', + `contact` varchar(20) NULL DEFAULT NULL COMMENT '旅行社联系人', + `contactMobileNumber` varchar(11) NULL DEFAULT NULL COMMENT '旅行社联系人手机', + `email` varchar(50) NULL DEFAULT NULL COMMENT '旅行社邮箱', + `maxUndertakeNumber` int NULL DEFAULT NULL COMMENT '最多承担人数', + `officialWebsite` varchar(100) NULL DEFAULT NULL COMMENT '旅行社官网', + `note` varchar(100) NULL DEFAULT NULL COMMENT '备注', + `year` int NULL DEFAULT NULL COMMENT '年度', + `isDisabled` tinyint(1) NULL DEFAULT NULL COMMENT '是否禁用', + `files` varchar(100) NULL DEFAULT NULL COMMENT '缩略图', + `signUpTravelAgency` tinyint(1) NULL DEFAULT NULL COMMENT '是否自由组团', + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养旅行社'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_audit` ( + `id` varchar(128) NOT NULL, + `auditor` varchar(128) NULL DEFAULT NULL, + `auditPass` tinyint(1) NULL DEFAULT NULL, + `auditTime` datetime NULL DEFAULT NULL, + `auditOpinion` text NULL, + `username` varchar(128) NULL DEFAULT NULL, + `loginname` varchar(128) NULL DEFAULT NULL, + `createdBy` varchar(32) NULL DEFAULT NULL COMMENT '创建人', + `createdAt` bigint NULL DEFAULT NULL COMMENT '创建时间', + `updatedBy` varchar(32) NULL DEFAULT NULL COMMENT '修改人', + `updatedAt` bigint NULL DEFAULT NULL COMMENT '修改时间', + `delFlag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记', + `opBy` varchar(32) NULL DEFAULT NULL, + `opAt` varchar(32) NULL DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养审核记录'; + +CREATE TABLE IF NOT EXISTS `staff_therapy_audit_state` ( + `stateId` int NOT NULL, + `stateName` varchar(128) NULL DEFAULT NULL, + `stateColor` varchar(128) NULL DEFAULT NULL, + PRIMARY KEY (`stateId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='疗休养审核状态'; + + +SET @staff_therapy_ddl = IF( + EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='staff_therapy_user'), + 'DO 0', 'CREATE VIEW `staff_therapy_user` AS SELECT u.*, u.arrivalAtSchoolDate AS schoolTime FROM vw_user u' +); +PREPARE staff_therapy_statement FROM @staff_therapy_ddl; +EXECUTE staff_therapy_statement; +DEALLOCATE PREPARE staff_therapy_statement; + +SET @staff_therapy_ddl = IF( + EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='staff_therapy_union'), + 'DO 0', 'CREATE VIEW `staff_therapy_union` AS SELECT u.*, u.name AS unionname FROM sys_union u' +); +PREPARE staff_therapy_statement FROM @staff_therapy_ddl; +EXECUTE staff_therapy_statement; +DEALLOCATE PREPARE staff_therapy_statement; + +SET @staff_therapy_ddl = IF( + EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema=DATABASE() AND table_name='staff_therapy_unit'), + 'DO 0', 'CREATE VIEW `staff_therapy_unit` AS SELECT u.* FROM sys_unit u' +); +PREPARE staff_therapy_statement FROM @staff_therapy_ddl; +EXECUTE staff_therapy_statement; +DEALLOCATE PREPARE staff_therapy_statement; + +START TRANSACTION; +SET @staff_therapy_now = CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED); + + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2710,'待分工会审核','#e6a23c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2710); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2715,'分工会审核不通过','#f56c6c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2715); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2720,'待选择线路分工会审核','#e6a23c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2720); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2725,'选择线路分工会不通过','#f56c6c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2725); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2730,'待校工会审核','#e6a23c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2730); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2735,'校工会审核不通过','#f56c6c' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2735); + +INSERT INTO `staff_therapy_audit_state` (`stateId`,`stateName`,`stateColor`) +SELECT 2750,'审核通过','#67c23a' +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_audit_state` WHERE `stateId`=2750); + +INSERT INTO `sys_config` (`configKey`,`configValue`,`note`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT 'staffTherapyRecuperationVersion','zjnu','职工疗休养独立子模块报名规则版本','',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_config` WHERE `configKey`='staffTherapyRecuperationVersion'); + +INSERT INTO `staff_therapy_config` + (`id`,`configName`,`isSnLine`,`isSwLine`,`travelAudit`,`bedInfo`,`familyInfo`,`outsideQuotaProportion`,`unionLineNumberConfigs`) +SELECT REPLACE(UUID(),'-',''),'智慧工会疗休养配置',0,0,0,1,1,0,JSON_ARRAY() +WHERE NOT EXISTS (SELECT 1 FROM `staff_therapy_config`); + +SET @staff_therapy_pc_module = COALESCE( + (SELECT m.`moduleId` FROM `sys_menu` m INNER JOIN `sys_module` s ON s.`id`=m.`moduleId` + WHERE m.`href` LIKE '/platform/recuperation%' AND m.`platform`='pc' ORDER BY m.`id` LIMIT 1), + (SELECT `id` FROM `sys_module` WHERE `name`='职工福利' AND `platform`='pc' ORDER BY `id` LIMIT 1), + REPLACE(UUID(),'-','') +); +INSERT INTO `sys_module` (`id`,`name`,`platform`,`sortNum`,`faIcon`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_pc_module,'职工福利','pc',50,'fa fa-heart','',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_module` WHERE `id`=@staff_therapy_pc_module); +SET @staff_therapy_module_name = (SELECT `name` FROM `sys_module` WHERE `id`=@staff_therapy_pc_module); +SET @staff_therapy_module_sort = (SELECT `sortNum` FROM `sys_module` WHERE `id`=@staff_therapy_pc_module); +SET @staff_therapy_h5_module = COALESCE( + (SELECT `id` FROM `sys_module` WHERE `name`=@staff_therapy_module_name AND `platform`='h5' ORDER BY `id` LIMIT 1), + REPLACE(UUID(),'-','') +); +INSERT INTO `sys_module` (`id`,`name`,`platform`,`sortNum`,`faIcon`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_h5_module,@staff_therapy_module_name,'h5',@staff_therapy_module_sort,'fa fa-heart','',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_module` WHERE `id`=@staff_therapy_h5_module); + +SET @staff_therapy_menu_root = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT('',LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=4 +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_root,'',@staff_therapy_next_path,'职工疗休养','menu','/platform/staffTherapyRecuperation','_self','fa fa-heart',1,0,'staffTherapyRecuperation', + @staff_therapy_next_location,1,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation'); + +SET @staff_therapy_root_path = (SELECT `path` FROM `sys_menu` WHERE `id`=@staff_therapy_menu_root); + +-- 基础设置 +SET @staff_therapy_menu_config = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyConfig' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_config,@staff_therapy_menu_root,@staff_therapy_next_path,'基础设置','menu','/platform/staffTherapyRecuperation?screen=config','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyConfig', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyConfig'); + +-- 旅行社管理 +SET @staff_therapy_menu_agency = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.travelAgency' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_agency,@staff_therapy_menu_root,@staff_therapy_next_path,'旅行社管理','menu','/platform/staffTherapyRecuperation?screen=agency','_self','fa fa-heart',1,0,'staffTherapyRecuperation.travelAgency', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.travelAgency'); + +-- 线路管理 +SET @staff_therapy_menu_line = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.line' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_line,@staff_therapy_menu_root,@staff_therapy_next_path,'线路管理','menu','/platform/staffTherapyRecuperation?screen=line','_self','fa fa-heart',1,0,'staffTherapyRecuperation.line', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.line'); + +-- 目的地管理 +SET @staff_therapy_menu_base = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheBaseManagement' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_base,@staff_therapy_menu_root,@staff_therapy_next_path,'目的地管理','menu','/platform/staffTherapyRecuperation?screen=base','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheBaseManagement', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheBaseManagement'); + +-- 分工会选择线路 +SET @staff_therapy_menu_branchSelect = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineFghSelect' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_branchSelect,@staff_therapy_menu_root,@staff_therapy_next_path,'分工会选择线路','menu','/platform/staffTherapyRecuperation?screen=branchSelect','_self','fa fa-heart',1,0,'staffTherapyRecuperation.lineFghSelect', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineFghSelect'); + +-- 校工会选择线路 +SET @staff_therapy_menu_schoolSelect = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineXghSelect' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_schoolSelect,@staff_therapy_menu_root,@staff_therapy_next_path,'校工会选择线路','menu','/platform/staffTherapyRecuperation?screen=schoolSelect','_self','fa fa-heart',1,0,'staffTherapyRecuperation.lineXghSelect', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineXghSelect'); + +-- 线路选择总览 +SET @staff_therapy_menu_overview = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineSelectionOverview' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_overview,@staff_therapy_menu_root,@staff_therapy_next_path,'线路选择总览','menu','/platform/staffTherapyRecuperation?screen=overview','_self','fa fa-heart',1,0,'staffTherapyRecuperation.lineSelectionOverview', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineSelectionOverview'); + +-- 线路组团 +SET @staff_therapy_menu_cluster = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineCluster' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_cluster,@staff_therapy_menu_root,@staff_therapy_next_path,'线路组团','menu','/platform/staffTherapyRecuperation?screen=cluster','_self','fa fa-heart',1,0,'staffTherapyRecuperation.lineCluster', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.lineCluster'); + +-- 线路调剂 +SET @staff_therapy_menu_adjustment = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.line.adjustment' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_adjustment,@staff_therapy_menu_root,@staff_therapy_next_path,'线路调剂','menu','/platform/staffTherapyRecuperation?screen=adjustment','_self','fa fa-heart',1,0,'staffTherapyRecuperation.line.adjustment', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.line.adjustment'); + +-- 参加人员导入 +SET @staff_therapy_menu_import = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.joinUser.import' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_import,@staff_therapy_menu_root,@staff_therapy_next_path,'参加人员导入','menu','/platform/staffTherapyRecuperation?screen=import','_self','fa fa-heart',1,0,'staffTherapyRecuperation.joinUser.import', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.joinUser.import'); + +-- 分工会审核 +SET @staff_therapy_menu_branchAudit = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyAudit' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_branchAudit,@staff_therapy_menu_root,@staff_therapy_next_path,'分工会审核','menu','/platform/staffTherapyRecuperation?screen=branchAudit','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyAudit', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyAudit'); + +-- 自由组团审核 +SET @staff_therapy_menu_travelAudit = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyTravelAudit' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_travelAudit,@staff_therapy_menu_root,@staff_therapy_next_path,'自由组团审核','menu','/platform/staffTherapyRecuperation?screen=travelAudit','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyTravelAudit', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyTravelAudit'); + +-- 校工会审核 +SET @staff_therapy_menu_schoolAudit = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyXghAudit' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_schoolAudit,@staff_therapy_menu_root,@staff_therapy_next_path,'校工会审核','menu','/platform/staffTherapyRecuperation?screen=schoolAudit','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyXghAudit', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyXghAudit'); + +-- 分工会查询 +SET @staff_therapy_menu_branchQuery = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyQuery' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_branchQuery,@staff_therapy_menu_root,@staff_therapy_next_path,'分工会查询','menu','/platform/staffTherapyRecuperation?screen=branchQuery','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyQuery', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyQuery'); + +-- 报名人员查询 +SET @staff_therapy_menu_userQuery = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyUserQuery' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_userQuery,@staff_therapy_menu_root,@staff_therapy_next_path,'报名人员查询','menu','/platform/staffTherapyRecuperation?screen=userQuery','_self','fa fa-heart',1,0,'staffTherapyRecuperation.TheRapyUserQuery', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.TheRapyUserQuery'); + +-- 查询统计 +SET @staff_therapy_menu_queryStatistics = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.queryStatics' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_queryStatistics,@staff_therapy_menu_root,@staff_therapy_next_path,'查询统计','menu','/platform/staffTherapyRecuperation?screen=queryStatistics','_self','fa fa-heart',1,0,'staffTherapyRecuperation.queryStatics', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.queryStatics'); + +-- 线路统计 +SET @staff_therapy_menu_lineStatistics = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.statistics' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_lineStatistics,@staff_therapy_menu_root,@staff_therapy_next_path,'线路统计','menu','/platform/staffTherapyRecuperation?screen=lineStatistics','_self','fa fa-heart',1,0,'staffTherapyRecuperation.statistics', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.statistics'); + +-- 旅行社月度统计 +SET @staff_therapy_menu_agencyStatistics = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.travelAgencyMonthlyStatistics' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_agencyStatistics,@staff_therapy_menu_root,@staff_therapy_next_path,'旅行社月度统计','menu','/platform/staffTherapyRecuperation?screen=agencyStatistics','_self','fa fa-heart',1,0,'staffTherapyRecuperation.travelAgencyMonthlyStatistics', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.travelAgencyMonthlyStatistics'); + +-- 分工会线路数量统计 +SET @staff_therapy_menu_unionStatistics = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.unionLineNumberStatistics' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_unionStatistics,@staff_therapy_menu_root,@staff_therapy_next_path,'分工会线路数量统计','menu','/platform/staffTherapyRecuperation?screen=unionStatistics','_self','fa fa-heart',1,0,'staffTherapyRecuperation.unionLineNumberStatistics', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.unionLineNumberStatistics'); + +SET @staff_therapy_menu_signup = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.signup' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT(@staff_therapy_root_path,LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=CHAR_LENGTH(@staff_therapy_root_path)+4 AND LEFT(`path`,CHAR_LENGTH(@staff_therapy_root_path))=@staff_therapy_root_path +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_signup,@staff_therapy_menu_root,@staff_therapy_next_path,'疗休养报名','menu','/platform/staffTherapyRecuperation?screen=signup','_self','fa fa-heart',1,0,'staffTherapyRecuperation.signup', + @staff_therapy_next_location,0,'pc',@staff_therapy_pc_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.signup'); + +SET @staff_therapy_menu_mobile = COALESCE((SELECT `id` FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.mobile' LIMIT 1),REPLACE(UUID(),'-','')); +SET @staff_therapy_next_path = ( + SELECT CONCAT('',LPAD(COALESCE(MAX(CAST(RIGHT(`path`,4) AS UNSIGNED)),0)+1,4,'0')) + FROM `sys_menu` WHERE CHAR_LENGTH(`path`)=4 +); +SET @staff_therapy_next_location = (SELECT COALESCE(MAX(`location`),0)+1 FROM `sys_menu`); +INSERT INTO `sys_menu` + (`id`,`parentId`,`path`,`name`,`type`,`href`,`target`,`icon`,`showit`,`disabled`,`permission`,`location`,`hasChildren`,`platform`,`moduleId`,`createdBy`,`createdAt`,`updatedBy`,`updatedAt`,`delFlag`) +SELECT @staff_therapy_menu_mobile,'',@staff_therapy_next_path,'职工疗休养','menu','/platform/staffTherapyRecuperation/mobile/index','_self','fa fa-heart',1,0,'staffTherapyRecuperation.mobile', + @staff_therapy_next_location,0,'h5',@staff_therapy_h5_module,'',@staff_therapy_now,'',@staff_therapy_now,0 +WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `permission`='staffTherapyRecuperation.mobile'); + + +INSERT INTO `sys_role_menu` (`roleId`,`menuId`) +SELECT r.`id`,m.`id` FROM `sys_role` r CROSS JOIN `sys_menu` m +WHERE r.`disabled`=0 AND r.`code` IN ('sysadmin','superadmin','A06','SchoolUnionMemberAdmin','SYSADMIN','SCHOOL_UNION_ADMIN','SCHOOL_UNION_WELFARE_ADMIN','SCHOOL_UNION_MEMBER_ADMIN') + AND m.`permission` IN ('staffTherapyRecuperation','staffTherapyRecuperation.TheRapyConfig','staffTherapyRecuperation.travelAgency','staffTherapyRecuperation.line','staffTherapyRecuperation.TheBaseManagement','staffTherapyRecuperation.lineFghSelect','staffTherapyRecuperation.lineXghSelect','staffTherapyRecuperation.lineSelectionOverview','staffTherapyRecuperation.lineCluster','staffTherapyRecuperation.line.adjustment','staffTherapyRecuperation.joinUser.import','staffTherapyRecuperation.TheRapyAudit','staffTherapyRecuperation.TheRapyTravelAudit','staffTherapyRecuperation.TheRapyXghAudit','staffTherapyRecuperation.TheRapyQuery','staffTherapyRecuperation.TheRapyUserQuery','staffTherapyRecuperation.queryStatics','staffTherapyRecuperation.statistics','staffTherapyRecuperation.travelAgencyMonthlyStatistics','staffTherapyRecuperation.unionLineNumberStatistics') + AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rel WHERE rel.`roleId`=r.`id` AND rel.`menuId`=m.`id`); + +INSERT INTO `sys_role_menu` (`roleId`,`menuId`) +SELECT r.`id`,m.`id` FROM `sys_role` r CROSS JOIN `sys_menu` m +WHERE r.`disabled`=0 AND r.`code` IN ('H03','H04','H06','BRANCH_UNION_ADMIN','BRANCH_UNION_CHAIRMAN') + AND m.`permission` IN ('staffTherapyRecuperation','staffTherapyRecuperation.line','staffTherapyRecuperation.TheBaseManagement','staffTherapyRecuperation.lineFghSelect','staffTherapyRecuperation.lineSelectionOverview','staffTherapyRecuperation.lineCluster','staffTherapyRecuperation.line.adjustment','staffTherapyRecuperation.TheRapyAudit','staffTherapyRecuperation.TheRapyTravelAudit','staffTherapyRecuperation.TheRapyQuery') + AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rel WHERE rel.`roleId`=r.`id` AND rel.`menuId`=m.`id`); + +INSERT INTO `sys_role_menu` (`roleId`,`menuId`) +SELECT r.`id`,m.`id` FROM `sys_role` r CROSS JOIN `sys_menu` m +WHERE r.`disabled`=0 AND r.`code` IN ('public','PUBLIC','MEMBER','sysadmin','superadmin','SYSADMIN') + AND m.`permission` IN ('staffTherapyRecuperation','staffTherapyRecuperation.signup','staffTherapyRecuperation.mobile') + AND NOT EXISTS (SELECT 1 FROM `sys_role_menu` rel WHERE rel.`roleId`=r.`id` AND rel.`menuId`=m.`id`); + +COMMIT; diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basic.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basic.js new file mode 100644 index 0000000..8d09792 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basic.js @@ -0,0 +1,185 @@ + +/** + * 民族 + * @type {string[]} + */ +const nation = [ + '汉族', + '蒙古族', + '回族', + '藏族', + '维吾尔族', + '苗族', + '彝族', + '壮族', + '布依族', + '朝鲜族', + '满族', + '侗族', + '瑶族', + '白族', + '土家族', + '哈尼族', + '哈萨克族', + '傣族', + '黎族', + '傈僳族', + '佤族', + '畲族', + '高山族', + '拉祜族', + '水族', + '东乡族', + '纳西族', + '景颇族', + '柯尔克孜族', + '土族', + '达翰尔族', + '么佬族', + '羌族', + '布朗族', + '撒拉族', + '毛南族', + '仡佬族', + '锡伯族', + '阿昌族', + '普米族', + '塔吉克族', + '怒族', + '乌孜别克族', + '俄罗斯族', + '鄂温克族', + '德昂族', + '保安族', + '裕固族', + '京族', + '塔塔尔族', + '独龙族', + '鄂伦春族', + '赫哲族', + '门巴族', + '珞巴族', + '基诺族' +]; + +const uploadFileType = ['jpg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'pdf'] +const docType = ['doc', 'docx', 'xls', 'xlsx', 'pdf'] + +const FILE_UPLOAD_ADDRESS = '/platform/staffTherapyRecuperation/common/uploadFile' +const FILE_DELETE_ADDRESS = '/platform/staffTherapyRecuperation/common/deleteFile' +const FILE_STREAM_PREVIEW_ADDRESS = '/platform/staffTherapyRecuperation/common/preview' + +Vue.component('m-page-loading', httpVueLoader('/components/staffbenefit/therapyRecuperation/mobile/MLoading.vue')) +Vue.component('m-table-loading', httpVueLoader('/components/staffbenefit/therapyRecuperation/mobile/MTableLoading.vue')) +Vue.component('m-card', httpVueLoader('/components/staffbenefit/therapyRecuperation/mobile/MCard.vue')) +Vue.component('vant-file-upload', httpVueLoader('/components/staffbenefit/therapyRecuperation/mobile/VantFileUpload.vue')) + +const GetQueryString = (name) => { + const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + const r = window.location.search.substr(1).match(reg); + if (r != null) return unescape(r[2]); + return ""; +} +const removeHTMLTag = (str) => { + str = str.replace(/<\/?[^>]*>/g, ''); //去除HTML tag + str = str.replace(/[ | ]*\n/g, '\n'); //去除行尾空白 + str = str.replace(/\n[\s| | ]*\r/g, '\n'); //去除多余空行 + str = str.replace(/ /ig, '');//去掉  + return str; +} + +const CREATE_PREVIEW_URL = (val) => { + return /^(https?:|data:|blob:|\/)/.test(val || "") ? val : FILE_STREAM_PREVIEW_ADDRESS + "?id=" + encodeURIComponent(val) +} + +const clone = (val) => { + return JSON.parse(JSON.stringify(val)) +} + +const toChinesNum = (num) => { + let changeNum = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']; + let unit = ["", "十", "百", "千", "万"]; + num = parseInt(num); + let getWan = (temp) => { + let strArr = temp.toString().split("").reverse(); + let newNum = ""; + for (let i = 0; i < strArr.length; i++) { + newNum = (i == 0 && strArr[i] == 0 ? "" : (i > 0 && strArr[i] == 0 && strArr[i - 1] == 0 ? "" : changeNum[strArr[i]] + (strArr[i] == 0 ? unit[0] : unit[i]))) + newNum; + } + return newNum; + } + let overWan = Math.floor(num / 10000); + let noWan = num % 10000; + if (noWan.toString().length < 4) { + noWan = "0" + noWan; + } + return overWan ? getWan(overWan) + "万" + getWan(noWan) : getWan(num); +} + +const loc = () => { + return location.href.replace(location.search, "").replace(location.hash, "") +} + +const modal = { + // 消息提示 + msg(content) { + vant.Toast(content) + }, + // 错误消息 + msgError(content) { + vant.Toast.fail(content) + }, + // 成功消息 + msgSuccess(content) { + vant.Toast.success(content) + }, + // 弹出提示 + alert(content) { + vant.Dialog.alert({ + title: '提示', + message: content + }).then(() => { + // on close + }); + }, + // 确认窗体 + confirm(content) { + return new Promise((resolve, reject) => { + vant.Dialog.confirm({ + title: '提示', + message: content, + }).then(() => { + resolve() + }).catch(() => { + // reject() + }) + }) + }, + // 提示信息 + showToast(option) { + if (typeof option === "object") { + vant.Toast(option) + } else { + vant.Toast.loading({ + message: option, + forbidClick: true, + loadingType: 'spinner', + duration: 2500 + }); + } + }, + // 打开遮罩层 + loading(content) { + vant.Toast.loading({ + message: content, + forbidClick: true, + overlay: true, + duration: 0 + }); + }, + // 关闭遮罩层 + closeLoading() { + vant.Toast.clear(); + } +} +Vue.prototype.$modal = modal diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basics.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basics.js new file mode 100644 index 0000000..52b865d --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/basics.js @@ -0,0 +1,125 @@ +const uploadFileType = ['jpg', 'png', 'doc', 'docx', 'xls', 'xlsx', 'pdf'] +const docType = ['doc', 'docx', 'xls', 'xlsx', 'pdf'] + +const FILE_UPLOAD_ADDRESS = '/platform/staffTherapyRecuperation/common/uploadFile' +const FILE_DELETE_ADDRESS = '/platform/staffTherapyRecuperation/common/deleteFile' +const FILE_STREAM_PREVIEW_ADDRESS = '/platform/staffTherapyRecuperation/common/preview' +const FILE_STREAM_DOWNLOAD_ADDRESS = '/platform/staffTherapyRecuperation/common/download' + +const preview = async (filename, id) => { + const suffix = filename.substring(filename.lastIndexOf('.') + 1) + if (!docType.includes(suffix.toLowerCase())) { + let image = new Image(); + image.src = FILE_STREAM_PREVIEW_ADDRESS + "?id=" + id + let viewer = new Viewer(image); + viewer.show(); + } else { + let pdfStreamUrl = encodeURIComponent(FILE_STREAM_PREVIEW_ADDRESS + '?id=' + id) //将路径转码 + window.open('/assets/platform/plugins/pdfJs/web/viewer.html?file=' + pdfStreamUrl, filename) + } +} + +const download = (id) => { + window.open(FILE_STREAM_DOWNLOAD_ADDRESS + '?id=' + id) +} + + +const PREVIEW_IMAGE = (val) => { + let image = new Image(); + image.src = FILE_STREAM_PREVIEW_ADDRESS + "?id=" + val + let viewer = new Viewer(image); + viewer.show(); +} + +const CREATE_PREVIEW_URL = (val) => { + return /^(https?:|data:|blob:|\/)/.test(val || "") ? val : FILE_STREAM_PREVIEW_ADDRESS + "?id=" + encodeURIComponent(val) +} + + +/** + * 遮盖层颜色 + * @type {string} + */ +const COVER_LAYER_COLOR = "rgba(0,0,0,.45)" + +/** + * 民族 + * @type {string[]} + */ +const nation = [ + '汉族', + '蒙古族', + '回族', + '藏族', + '维吾尔族', + '苗族', + '彝族', + '壮族', + '布依族', + '朝鲜族', + '满族', + '侗族', + '瑶族', + '白族', + '土家族', + '哈尼族', + '哈萨克族', + '傣族', + '黎族', + '傈僳族', + '佤族', + '畲族', + '高山族', + '拉祜族', + '水族', + '东乡族', + '纳西族', + '景颇族', + '柯尔克孜族', + '土族', + '达翰尔族', + '么佬族', + '羌族', + '布朗族', + '撒拉族', + '毛南族', + '仡佬族', + '锡伯族', + '阿昌族', + '普米族', + '塔吉克族', + '怒族', + '乌孜别克族', + '俄罗斯族', + '鄂温克族', + '德昂族', + '保安族', + '裕固族', + '京族', + '塔塔尔族', + '独龙族', + '鄂伦春族', + '赫哲族', + '门巴族', + '珞巴族', + '基诺族' +]; + +const loc = () => { + return location.href.replace(location.search, "").replace(location.hash, "") +} + +const clone = (obj) => { + return JSON.parse(JSON.stringify(obj)) +} + +const calcTableHeight = (eleIds = []) => { + if (eleIds) { + eleIds.forEach(e_id => { + const ele = document.querySelector('#' + e_id) + if (ele) { + ele.style.height = (innerHeight - ele.getBoundingClientRect().top - parseInt(ele.dataset.bottom)) + 'px' + } + }) + } +} diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/compat.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/compat.js new file mode 100644 index 0000000..370338f --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/compat.js @@ -0,0 +1,42 @@ +const sublime = { + showLoadingbar() { + if (!document.getElementById('therapy-loading')) { + const bar = document.createElement('div'); + bar.id = 'therapy-loading'; + document.body.appendChild(bar); + } + }, + closeLoadingbar() { + const bar = document.getElementById('therapy-loading'); + if (bar) bar.remove(); + } +}; + +$.ajaxSetup({ + traditional: true, + error(xhr) { + sublime.closeLoadingbar(); + const message = xhr.responseJSON && xhr.responseJSON.msg || '请求失败,请稍后重试'; + if (window.ELEMENT) ELEMENT.Message.error(message); + else if (window.vant) vant.Toast.fail(message); + } +}); + +Vue.prototype.$downLoad = function(url, data = {}) { + const query = $.param(data, true); + window.open(url + (url.includes('?') ? '&' : '?') + query); +}; +Vue.prototype.$download = Vue.prototype.$downLoad; +Vue.prototype.$viewImage = function(url) { + const address = CREATE_PREVIEW_URL(url); + if (window.vant) vant.ImagePreview([address]); + else window.open(address); +}; +window.viewImage = Vue.prototype.$viewImage; + +// v3 views use the same helper for stored file IDs and v4 download URLs. +window.therapyPreview = function(value) { + if (!value) return ''; + return /^(https?:|data:|blob:|\/)/.test(value) ? value : + '/platform/staffTherapyRecuperation/common/preview?id=' + encodeURIComponent(value); +}; diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js new file mode 100644 index 0000000..d3dc359 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/component.js @@ -0,0 +1,129 @@ +Vue.component('vi-title', { + props: ['title'], + template: ` +
+
+
+ {{ title }} +
+
+ ` +}) + +Vue.component('vi-title2', { + props: ['title'], + template: ` + +
+ +
+ +
+ +
+
+ + ` +}) + +Vue.component('vi-table-state', { + props: ['state'], + template: ` + {{ state.stateName }} + ` +}) +Vue.component('more', { + props: {more: {type: Boolean, default: false}}, + template: ` + + {{ more ? '收起' : '展开' }} + `, + model: { + prop: 'more', + event: 'change' + } +}) + +Vue.component('table-tool', { + props: { + label: {type: String}, + app: {} + }, + data() { + return { + checkedFields: [], + columns: [], + } + }, + methods: { + tableSizeChange(command) { + const {size} = command + this.app.tableSizeChange(size) + }, + columnChange() { + this.app.columnChange(this.columns.filter(v => this.checkedFields.includes(v.prop))) + }, + getColumns() { + const {tableColumns} = this.app + if (!tableColumns) { + return + } + this.columns = tableColumns + this.checkedFields = this.columns.filter(v => v.checked !== 0).map(v => v.prop) + this.columnChange() + }, + }, + created() { + this.getColumns() + }, + template: ` + + +
+ +
+ +
+ + +
+
+ +
+ + +
+ + Mini + Small + Medium + Large + +
+ + + +
+ + {{ + field.label + }} + + +
+ +
+ +
+
+ + +
+
+
+ `, +}) \ No newline at end of file diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/common.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/common.css new file mode 100644 index 0000000..deb2334 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/common.css @@ -0,0 +1,198 @@ +[v-cloak] { + display: none +} + +#app { + background-color: rgb(240, 242, 245); + height: 100%; + overflow-y: auto; +} + +.platform .guava-card .slot-class { + height: calc(100vh - 180px); +} + +/** +图片预览 + */ +.viewer-container { + z-index: 10000; +} + +/** + 富文本层级调整 + */ +.w-e-toolbar{ + z-index: 1001!important; +} + +.w-e-text-container{ + z-index: 1000!important; +} + + +/** + 搜索栏样式 + */ +.search { + display: flex; + flex-wrap: wrap; + margin-bottom: -15px; +} + +.search .search-item { + display: flex; + align-items: center; + margin-bottom: 15px; + box-sizing: border-box; + width: calc((100% - 160px) / 3); + overflow: hidden; +} + +.search .search-query { + width: 160px; + margin-bottom: 15px; + overflow: hidden; + white-space: nowrap; +} + +.search .search-item:not(:last-child) { + padding-right: 40px; +} + +.search .search-item-label { + color: rgb(100, 100, 100); + margin-right: 10px; + width: 80px; + min-width: 80px; + overflow: hidden; +} + +.search .search-item-option { + min-width: calc(100% - 80px - 10px); + overflow: hidden; +} + +@media screen and (max-width: 1200px) { + .search .search-item { + width: calc((100% - 160px) / 2); + } +} + +@media screen and (max-width: 992px) { + .search .search-item { + width: 100%; + } + + .search .search-item:not(:last-child) { + padding-right: 0; + } +} + + +.platform .vi-table table thead tr th { + background-color: #fafafa !important; +} + +.table-tool-group { + margin-left: 15px; + overflow: hidden; + border-radius: 20px; + display: flex; +} + +.table-tool-group .table-tool-group-item { + width: 40px; + height: 40px; + display: flex; + justify-content: center; + align-items: center; + cursor: pointer; + background-color: rgba(240, 240, 240, .7); + font-weight: bolder; + transition: all 250ms; +} + +.table-tool-group .table-tool-group-item:not(:last-child) { + border-right: 1px solid white; +} + +.table-tool-group .table-tool-group-item:hover { + color: white; + background-color: rgb(64, 158, 255); +} + +.width-100 { + width: 100%; +} + +.ie-must-go-die { + position: fixed; + left: 0; + top: 0; + right: 0; + bottom: 0; +} + +.ie-must-go-die .ie-container { + position: absolute; + top: 40%; + left: 33%; + text-align: center; + color: #000; +} + +.ie-must-go-die .ie-container h1 { + font-size: 28px; + margin-bottom: 36px; +} + +.ie-must-go-die .ie-container p { + font-size: 16px; + line-height: 24px; + margin-bottom: 16px; +} + +.ie-must-go-die .ie-container a { + display: block; + color: inherit; +} + +.ie-must-go-die .ie-container a:hover { + text-decoration: underline; +} + +.ie-must-go-die .ie-container a:visited { + color: inherit; +} + +.el-loading-spinner i { + font-size: 28px; +} + +.el-loading-spinner i, .el-loading-spinner p { + /*color: white !important;*/ +} + +.w-e-toolbar { + background-color: white !important; + border-color: #DCDFE6 !important; +} + +.w-e-text-container { + border-color: #DCDFE6 !important; +} + +.el-radio-group label { + margin-bottom: 0 !important; +} + + +/* 滚动条整体部分 */ +.main-navigation::-webkit-scrollbar { + display: none; +} + +.main-navigation { + border-right: 3px solid rgb(240, 240, 240); +} \ No newline at end of file diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/elmain.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/elmain.css new file mode 100644 index 0000000..b554ca9 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/elmain.css @@ -0,0 +1,152 @@ +/*.el-dialog__header{*/ +/*border-bottom: 1px solid #e5e5e5;*/ +/*}*/ + +/*.el-dialog__footer{*/ +/*border-top: 1px solid #e5e5e5;*/ +/*}*/ +.el-table-container { + padding-top: 54px; + padding-left: 5px; + padding-right: 5px; +} + +.el-pagination-container { + background-color: #fff; +} + +.el-pagination { + height: 50px; + overflow: hidden; + display: flex; + align-items: center; +} + +.el-pagination button, .el-pagination span:not([class*=suffix]) { + line-height: 50px; + height: 50px; +} + +a .collapsed { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIW…aIJN0bgQRgIjnlmn1heSO5PE6Y2YXe+5Cr5+h++gs12AcAS6FS+7YOsj4AAAAASUVORK5CYII=); +} + +a .expanded { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIW…EYRYBPOB0gBShKwKGA////48VtbW3/8clTnBIH3gCKkzJgAGvBX0dDm0sCAAAAAElFTkSuQmCC); +} + +.ms-tree-space { + position: relative; + top: 1px; + display: inline-block; + font-family: 'Glyphicons Halflings'; + font-style: normal; + font-weight: 400; + line-height: 1; + width: 18px; + height: 14px; +} + +.ms-tree-space::before { + content: "" +} + +.el-table__expand-icon--expanded { + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} + +.el-table-expand { + font-size: 0; +} +.el-table-expand label { + width: 90px; + color: #99a9bf; + font-size: 12px; +} +.el-table-expand .el-form-item{ + margin-bottom: 2px; + margin-right: 0; + width: 50%; + display: inline-block; + vertical-align: top; +} +.el-table-expand .el-form-item__content { + margin-right: 0; + margin-bottom: 0; + font-size: 12px; + display: inline-block; + vertical-align: top; + position: relative; +} + +.el-table-expand-line { + font-size: 0; +} +.el-table-expand-line label { + width: 90px; + color: #99a9bf; + font-size: 12px; +} +.el-table-expand-line .el-form-item{ + margin-bottom: 2px; + margin-right: 0; + width: 100%; + display: inline-block; + vertical-align: top; +} +.el-table-expand-line .el-form-item__content { + margin-right: 0; + margin-bottom: 0; + font-size: 12px; + display: inline-block; + vertical-align: top; + position: relative; +} + +.el-table__body-wrapper { + scrollbar-width: auto; /* firefox */ + -ms-overflow-style: auto; /* IE 10+ */ + overflow-x: auto; + overflow-y: auto; +} + +.el-table__body-wrapper::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +.el-table__body-wrapper::-webkit-scrollbar-thumb { + border-radius: 4px; + background-color: rgba(144, 147, 153, .35); +} + +.el-table__body-wrapper::-webkit-scrollbar-track { + background-color: #f5f7fa; +} + + +.el-upload__tip { + margin-top: 0px; + color: #c33714; +} + +.el-dialog { + width: 60%; +} + +.el-table__empty-block { + width: 100% !important; + min-height: 300px; + background: url("/none.png") no-repeat center center; + background-size: 360px 260px; +} + +.el-table__empty-text { + display: block; + position: absolute; + bottom: 80px; + height: 40px; + line-height: 40px; + /*display: none !important;*/ +} diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/main.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/main.css new file mode 100644 index 0000000..349378e --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/main.css @@ -0,0 +1,7348 @@ +body { + background: #f6f6f6; + color: #59595a; + line-height: 1.5; + direction: ltr; + -webkit-font-smoothing: antialiased; +} + +html, body, #mainApp { + height: 100%; +} + +h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 { + line-height: 1.1; +} + +.bolder { + font-weight: 800; +} + +a { + text-decoration: none; + -webkit-transition: 0.25s; + transition: 0.25s; +} + +a:visited, a:active, a:focus, a:hover { + text-decoration: none; + outline: 0; +} + +[class^="ti-"].pull-right, [class*=" ti-"].pull-right { + line-height: inherit; +} + +hr { + display: block; + margin: 1em 0; + padding: 0; + height: 1px; + border: 0; + border-top: 1px solid #e3e6f3; +} + +img { + max-width: 100%; + height: auto; +} + +img { + -ms-interpolation-mode: bicubic; +} + +.img-rounded { + border-radius: 2px; +} + +.img-circle { + border-radius: 50%; +} + +.avatar { + position: relative; + display: inline-block; + width: 100%; +} + +.avatar-lg { + width: 128px; +} + +.avatar-md { + width: 64px; +} + +.avatar-sm { + width: 32px; +} + +.avatar-xs { + width: 16px; +} + +.bordered-avatar { + border: 3px solid #fff; + background-color: #eaecf6; +} + +[contenteditable], [contenteditable]:hover, [contenteditable]:active { + outline: 0; +} + +blockquote { + margin: 15px 0; + padding: 10px; + border: 0; + font-size: 13px; + float: left; + display: block; +} + +blockquote:before { + color: #E2E4E9; + font-family: Georgia, serif; + content: "“"; + font-size: 40px; + margin-right: 10px; + float: left; + line-height: 1; +} + +blockquote p { + display: inline; +} + +.pullquote { + font-style: italic; + display: block; + float: left; + font-size: 1.6em; + width: 55%; +} + +.pullquote:before { + font-family: Georgia, serif; + content: "“"; + font-style: normal; + font-size: 40px; + float: left; + color: #E2E4E9; +} + +.drop-cap { + float: left; + font-size: 75px; + line-height: 60px; + padding-top: 4px; + padding-right: 8px; + font-family: Georgia; +} + +.drop-cap.boxed { + padding: 10px; + margin: 0 5px 5px 0; + border-radius: 2px; +} + +ol { + list-style-position: outside; + list-style-type: decimal; +} + +ul { + list-style-position: outside; + list-style-type: disc; + line-height: 1.5; +} + +ol.list-style-none, ul.list-style-none { + list-style: none; + padding: 0; +} + +.nav { + padding: 0; +} + +.pageload { + width: 100%; + height: 100%; + position: fixed; + top: 0; + background-color: rgba(255, 255, 255, 0.9); + z-index: 99999; +} + +.pageload .loader { + position: absolute; + margin: -12px 0 0 -12px; + top: 50%; + left: 50%; + text-align: center; + width: 24px; +} + +.loader:after { + border-radius: 50%; + width: 24px; + height: 24px; + margin: 0 auto; + display: block; + z-index: 2000; + border-radius: 24px; + content: ""; + -webkit-animation: spinner 400ms linear infinite; + -ms-animation: spinner 400ms linear infinite; + animation: spinner 400ms linear infinite; +} + +@-webkit-keyframes spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@-ms-keyframes spinner { + 0% { + -ms-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@keyframes spinner { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +@media print { + .content-wrap { + width: 100%; + } + + .sidebar, + .header, + .no-print { + display: none; + } +} + +/* + * + * $Header layout + * + * Core theme layout styles + */ +/* header element */ +.header { + min-height: 50px; + max-height: 50px; + overflow: hidden; + z-index: 1000; + border-radius: 0; + border: 0; + margin: 0; + background-color: #fff; + display: inline-flex; + position: fixed; + left: 0; + right: 0; + top: 0; + /* Branding */ +} + +.header li:hover, +.header li a:hover, +.header li a:active { + background: transparent; +} + +.header .brand { + width: 250px; + max-height: 50px; + height: 50px; + background: #001529; +} + +.header .brand .navbar-brand { + font-size: 14px; + font-weight: 600; + letter-spacing: 1px; + padding-top: 0; + padding-bottom: 0; + line-height: 50px; + padding-left: 0; + width: 100%; +} + +.header .brand .navbar-brand img { + display: inline-block; + height: 80%; + width: 90%; +} + +.header .brand .navbar-brand .heading-font { + font-weight: 600; + font-size: 12px; + line-height: 12px; + font-style: italic; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} + +.o_hide { + display: none !important; +} + +.header .navbar-nav { + margin: 0; + display: flex; + align-items: center; + height: 50px; +} + +.header .navbar-nav li { + height: 50px; + line-height: 50px; +} + +.header .navbar-nav li a { + color: #000000; +} + +.header .navbar-nav li:hover { + /*background: #f5f5f5;*/ +} + +.header .navbar-right { + position: absolute; + right: 10px +} + +.header .navbar-nav > li > a { + padding-top: 15px; + padding-bottom: 15px; + max-height: 50px; +} + +.header .navbar-nav > li > a:focus { + background-color: transparent; +} + +.header .header-avatar { + width: 32px; + margin-top: -6px; +} + +.header > .nav > li > a > .badge { + position: absolute; + top: 8px; + right: 2px; + width: 16px; + height: 16px; + font-size: 11px; + line-height: 1.5; + text-align: center; + padding: 0; +} + +.header .header-search { + position: relative; +} + +.header .header-search .search-container { + top: 10px; + width: 0; + -webkit-transition: width 300ms; + transition: width 300ms; + position: absolute; + left: 40px; +} + +.header .header-search .search-container .search { + height: 30px; + border: 0; + padding: 0; + text-indent: 10px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.header .header-search .toggle-search { + padding: 5px 9px !important; + margin: 10px; + width: 30px; + height: 30px; + border-radius: 2px; +} + +.header .header-search.open > a { + z-index: 1001; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +.header .header-search.open .search-container { + width: 300px; +} + +.header .header-search.open .search-container .search { + padding-right: 12px; +} + +/** + 模块应用中心 + */ +.appCenterPopover { + padding: 0 !important; +} + +.appCenterCard .el-card__header { + padding: 8px 10px !important; +} + +.appCenterPopover .entranceDetail { + border-radius: 6px; + text-align: center; + cursor: pointer; + line-height: 1; + color: #606060; + padding: 5px; +} + +.appCenterPopover .entranceDetail:hover, .appCenterPopover .entranceDetail-selected { + background-color: #e5edff; + color: #3177fd; +} + +.appCenterCard .entranceIcon { + position: relative; + width: 50px; + height: 50px; + margin: 8px auto 6px; + color: #fff; +} + +.layout { + display: flex; + padding-top: 50px; + height: 100%; +} + +/* + * $Sidebar layout + * + * Core theme layout styles + */ +/* main sidebar */ + +.sidebar { + min-width: 250px; + width: 250px; + height: calc(100vh - 50px); + overflow-y: auto; + background: #001529; +} + +.sidebar::-webkit-scrollbar { + display: none; +} + +.sidebar .el-menu { + border-right: 0; +} + +.sidebar .el-menu i { + width: 24px; + height: 18px; + text-align: center; + margin-right: 5px; +} + +.sidebar .nav-title { + font-size: 11px; + padding: 25px 15px 0; + letter-spacing: 1px; +} + +.sidebar > footer { + position: absolute; + bottom: 0; + width: 100%; +} + +.nav .dropdown .dropdown-menu li a .toggle-accordion:before { + font-family: "themify"; + font-style: normal; + font-weight: normal; + content: "\e649"; +} + +.nav .dropdown .dropdown-menu > li .sub-menu { + font-size: 12px; + padding-left: 0; +} + +.nav .dropdown .dropdown-menu .sub-menu > li { + list-style: none; +} + +.nav .dropdown .dropdown-menu .sub-menu > li > a { + padding: 3px 30px; + clear: both; + font-size: 12px; + list-style: none; + line-height: 1.5; + color: #333; + white-space: nowrap; + float: left; + text-align: left; + width: 100%; +} + +.nav .dropdown .dropdown-menu .sub-menu > li > a:hover, .nav .dropdown .dropdown-menu .sub-menu > li > a:focus { + color: #262626; + text-decoration: none; + background-color: #dcdff0; +} + +/* + * $Content Layout + * + * Core theme layout styles + */ +/* main app area */ +.main-content { + background: #fff; + width: calc(100vw - 250px); +} + +/* Loading wrapper */ +.loader { + top: 50%; + -webkit-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); + position: relative; + margin-left: auto; + margin-right: auto; + text-align: center; +} + +.ti-caret:before { + font-size: 10px !important; +} + +.cover { + background-size: cover; + background-repeat: no-repeat; + background-position: center; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + width: 100%; + height: 100%; + z-index: 0; +} + +.overlay { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + opacity: 0.95; + filter: alpha(opacity=95); + z-index: 0; +} + +/* Layout options */ +.fixed-scroll.boxed > .header { + width: inherit; +} + +.fixed-scroll > .header { + position: fixed; +} + +.fixed-scroll .wrapper { + position: relative; +} + +.fixed-scroll .main-navigation { + position: relative; + overflow: visible; +} + +.boxed { + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 768px) { + .boxed { + width: 750px; + } +} + +@media (min-width: 992px) { + .boxed { + width: 970px; + } +} + +@media (min-width: 1200px) { + .boxed { + width: 1170px; + } +} + +.app.horizontal-layout > .header .brand { + background-color: transparent; +} + +@media (max-width: 767px) { + .app.horizontal-layout > .header .navbar-collapse .dropdown-menu { + position: relative !important; + top: auto; + box-shadow: none; + } + + .app.horizontal-layout .nav li:before, + .app.horizontal-layout .nav li:after { + content: " "; + display: table; + } + + .app.horizontal-layout .nav li:after { + clear: both; + } +} + +.language-dropdown .flag { + width: 16px; + margin-top: -2px; +} + +.right-menu .header-search .search-container { + left: auto; + right: 40px; +} + +.right-menu .header-search .search-container .search { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +.right-menu .header-search.open > a { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + + +.right-menu.small-menu .brand { + float: right; +} + +.right-menu.small-menu .main-navigation > ul > li .sub-menu { + border-left: 1px solid #e3e6f3 !important; + border-right: 0 !important; +} + +[data-animation] { + visibility: hidden; +} + +.animated { + visibility: visible !important; +} + +.visible { + visibility: visible; +} + +.arrow { + position: absolute; + height: 0; + width: 0; +} + +.arrow:after { + border-width: 10px; + content: ""; + border-color: rgba(0, 0, 0, 0); + border-style: solid; + display: block; +} + +.arrow.left:after { + border-left-color: #fff; + border-right-width: 0; + content: " "; +} + +.arrow.left, +.arrow.right { + top: 50%; + margin-top: -10px; +} + +.arrow.left { + left: 0; +} + +.arrow.right:after { + border-right-color: #fff; + border-left-width: 0; + content: " "; +} + +.arrow.right { + right: 10px; +} + +.fffix { + position: relative; + display: block; + height: 100%; + width: 100%; +} + +/* + * $Color Scheme + * + */ +.fc-event { + border: 1px solid #4f5061; + background-color: #4f5061; + color: #fff; +} + +/* + * Color Variant: Primary; + * + */ +.bg-primary { + background-color: #1582dc; + color: #ffffff; +} + +.bg-primary a { + color: #ffffff; +} + +.bg-primary a:active, +.bg-primary a:focus, +.bg-primary a:hover { + color: #e6e6e6; + text-decoration: none; + outline: 0; +} + +.bg-primary .nav > li:hover > a, +.bg-primary .nav > li:focus > a, +.bg-primary .nav > li:active > a, +.bg-primary .nav > li.active > a, +.bg-primary .nav > li > a:hover, +.bg-primary .nav > li > a:focus { + background-color: #147ace; +} + +/* + * Color Variant: Default; + * + */ +.bg-default { + background-color: #eaecf6; + color: #59595a; +} + +.bg-default a { + color: #59595a; +} + +.bg-default a:active, +.bg-default a:focus, +.bg-default a:hover { + color: #404040; + text-decoration: none; + outline: 0; +} + +.bg-default .nav > li:hover > a, +.bg-default .nav > li:focus > a, +.bg-default .nav > li:active > a, +.bg-default .nav > li.active > a, +.bg-default .nav > li > a:hover, +.bg-default .nav > li > a:focus { + background-color: #dfe2f1; +} + +/* + * Color Variant: Warning; + * + */ +.bg-warning { + background-color: #daac16; + color: #ffffff; +} + +.bg-warning a { + color: #ffffff; +} + +.bg-warning a:active, +.bg-warning a:focus, +.bg-warning a:hover { + color: #e6e6e6; + text-decoration: none; + outline: 0; +} + +.bg-warning .nav > li:hover > a, +.bg-warning .nav > li:focus > a, +.bg-warning .nav > li:active > a, +.bg-warning .nav > li.active > a, +.bg-warning .nav > li > a:hover, +.bg-warning .nav > li > a:focus { + background-color: #cca115; +} + +/* + * Color Variant: Success; + * + */ +.bg-success { + background-color: #15db81; + color: #ffffff; +} + +.bg-success a { + color: #ffffff; +} + +.bg-success a:active, +.bg-success a:focus, +.bg-success a:hover { + color: #e6e6e6; + text-decoration: none; + outline: 0; +} + +.bg-success .nav > li:hover > a, +.bg-success .nav > li:focus > a, +.bg-success .nav > li:active > a, +.bg-success .nav > li.active > a, +.bg-success .nav > li > a:hover, +.bg-success .nav > li > a:focus { + background-color: #14cd79; +} + +/* + * Color Variant: Info; + * + */ +.bg-info { + background-color: #15acdc; + color: #ffffff; +} + +.bg-info a { + color: #ffffff; +} + +.bg-info a:active, +.bg-info a:focus, +.bg-info a:hover { + color: #e6e6e6; + text-decoration: none; + outline: 0; +} + +.bg-info .nav > li:hover > a, +.bg-info .nav > li:focus > a, +.bg-info .nav > li:active > a, +.bg-info .nav > li.active > a, +.bg-info .nav > li > a:hover, +.bg-info .nav > li > a:focus { + background-color: #14a1ce; +} + +/* + * Color Variant: Danger; + * + */ +.bg-danger { + background-color: #da3e16; + color: #ffffff; +} + +.bg-danger a { + color: #ffffff; +} + +.bg-danger a:active, +.bg-danger a:focus, +.bg-danger a:hover { + color: #e6e6e6; + text-decoration: none; + outline: 0; +} + +.bg-danger .nav > li:hover > a, +.bg-danger .nav > li:focus > a, +.bg-danger .nav > li:active > a, +.bg-danger .nav > li.active > a, +.bg-danger .nav > li > a:hover, +.bg-danger .nav > li > a:focus { + background-color: #cc3a15; +} + +/* + * Color Variant: White; + * + */ +.bg-white { + background-color: #ffffff; + color: #59595a; +} + +.bg-white a { + color: #59595a; +} + +.bg-white a:active, +.bg-white a:focus, +.bg-white a:hover { + color: #404040; + text-decoration: none; + outline: 0; +} + +.bg-white .nav > li:hover > a, +.bg-white .nav > li:focus > a, +.bg-white .nav > li:active > a, +.bg-white .nav > li.active > a, +.bg-white .nav > li > a:hover, +.bg-white .nav > li > a:focus { + background-color: #f7f7f7; +} + +.bg-white .nav > li:hover > a, +.bg-white .nav > li:focus > a, +.bg-white .nav > li:active > a, +.bg-white .nav > li.active > a, +.bg-white .nav > li > a:hover, +.bg-white .nav > li > a:focus { + background-color: rgba(0, 0, 0, 0.1); +} + +/* + * Text Color Variant + * + */ +.text-primary, +.text-primary a { + color: #1582dc; +} + +.text-primary:focus, +.text-primary a:focus { + color: #0e5996; +} + +.text-default, +.text-default a { + color: #eaecf6; +} + +.text-default:focus, +.text-default a:focus { + color: #b4bcdf; +} + +.text-warning, +.text-warning a { + color: #daac16; +} + +.text-warning:focus, +.text-warning a:focus { + color: #95750f; +} + +.text-success, +.text-success a { + color: #15db81; +} + +.text-success:focus, +.text-success a:focus { + color: #0e9558; +} + +.text-info, +.text-info a { + color: #15acdc; +} + +.text-info:focus, +.text-info a:focus { + color: #0e7596; +} + +.text-white, +.text-white a { + color: #ffffff; +} + +.text-white:focus, +.text-white a:focus { + color: #d9d9d9; +} + +.text-danger, +.text-danger a { + color: #da3e16; +} + +.text-danger:focus, +.text-danger a:focus { + color: #952a0f; +} + +.text-muted, +.text-muted a { + color: #b3b3b3; +} + +.text-muted:focus, +.text-muted a:focus { + color: #8c8c8c; +} + +/* + * Bootstrap $Badge + * + */ +.badge { + font-size: 11px; + font-weight: 400; + padding: 3px 6px; +} + +.badge.badge-top { + position: relative; + top: -10px; +} + +/* + * Bootstrap $Breadcrumb + * + */ +.breadcrumb { + background-color: #ffffff; + border-radius: 2px; +} + +.breadcrumb > li + li:before { + padding: 0 5px; + content: "\f105\00a0"; + font-family: FontAwesome; +} + +/* + * $Presentation styles + * + */ +pre { + color: #59595a; + background-color: #EFF2F5; + border: 1px solid #e3e6f3; + border-radius: 2px; + font-size: 11px; + font-family: Monaco, Menlo, Consolas, "Courier New", monospace; +} + +/* + * Bootstrap $Pagination + * + */ +.pagination { + border-radius: 2px; +} + +.pagination > li > a, +.pagination > li > span { + border-color: #e3e6f3; +} + +.pagination > li > a:hover, +.pagination > li > span:hover { + background-color: #f5f6fb; + border-color: #d1d5eb; +} + +.pagination > li:first-child > a, +.pagination > li:first-child > span { + border-radius: 2px 0 0 2px; +} + +.pagination > li:last-child > a, +.pagination > li:last-child > span { + border-radius: 0 2px 2px 0; +} + +/* + * Bootstrap $Popover + * + */ +.popover { + box-shadow: none; +} + +.popover .popover-title { + font-size: 13px; + border-bottom: 1px solid #e3e6f3; + background-color: #eaecf6; +} + +/* + * Bootstrap $Tooltip + * + */ +.tooltip-inner { + border-radius: 2px; + background-color: 2px; + background: #4f5061; + padding: 10px; +} + +.tooltip.top .tooltip-arrow { + border-top-color: #4f5061; +} + +.tooltip.top-left .tooltip-arrow { + border-top-color: #4f5061; +} + +.tooltip.top-right .tooltip-arrow { + border-top-color: #4f5061; +} + +.tooltip.right .tooltip-arrow { + border-right-color: #4f5061; +} + +.tooltip.left .tooltip-arrow { + border-left-color: #4f5061; +} + +.tooltip.bottom .tooltip-arrow { + border-bottom-color: #4f5061; +} + +.tooltip.bottom-left .tooltip-arrow { + border-bottom-color: #4f5061; +} + +.tooltip.bottom-right .tooltip-arrow { + border-bottom-color: #4f5061; +} + +.tooltip.in { + opacity: 1; + filter: alpha(opacity=100); +} + +/* + * Modal + * + */ +.modal-content { + border-radius: 4px; + box-shadow: none; +} + +/* + * Well + * + */ +.well { + border: 1px solid #e3e6f3; + background-color: #eaecf6; + border-radius: 2px; + box-shadow: none; +} + +/* + * List group + * + */ +.list-group-item { + border: 1px solid #e3e6f3; +} + +a.list-group-item:hover, +a.list-group-item:focus { + background-color: #fcfcfe; +} + +/* + * Bootstrap $Tables + * + */ +.table > thead > tr > th { + border-bottom: 1px solid #e3e6f3; +} + +.table > thead > tr > th, +.table > tbody > tr > th, +.table > tfoot > tr > th, +.table > thead > tr > td, +.table > tbody > tr > td, +.table > tfoot > tr > td { + border-color: #e3e6f3; +} + +.table-hover > tbody > tr:hover > td, +.table-hover > tbody > tr:hover > th { + background-color: #eaeaf2; +} + +.table-hover > tbody > tr > td.active:hover, +.table-hover > tbody > tr > th.active:hover, +.table-hover > tbody > tr.active:hover > td, +.table-hover > tbody > tr.active:hover > th { + background-color: #eaeaf2; +} + +.table-striped > tbody > tr:nth-child(odd) > td, +.table-striped > tbody > tr:nth-child(odd) > th { + background-color: transparent; +} + +.table-striped > tbody > tr:nth-child(even) > td, +.table-striped > tbody > tr:nth-child(even) > th { + background-color: #fafafc; +} + +.table-bordered > thead > tr > th, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > tbody > tr > td, +.table-bordered > tfoot > tr > td { + border-right: 0; + border-bottom: 0; + border-left: 1px solid #e3e6f3; +} + +.table-bordered > thead > tr > th:first-child, +.table-bordered > tbody > tr > th:first-child, +.table-bordered > tfoot > tr > th:first-child, +.table-bordered > thead > tr > td:first-child, +.table-bordered > tbody > tr > td:first-child, +.table-bordered > tfoot > tr > td:first-child { + border-left: 0; +} + +.table-bordered { + border: 1px solid #e3e6f3; + border-radius: 2px; + border-collapse: separate; +} + +/* No More tables */ +@media (max-width: 767px) { + /* Source:: http://elvery.net/demo/responsive-tables/#no-more-tables */ + /* Force table to not be like tables anymore */ + .no-more-tables table, + .no-more-tables thead, + .no-more-tables tbody, + .no-more-tables th, + .no-more-tables td, + .no-more-tables tr { + display: block; + } + + /* Hide table headers (but not display: none;, for accessibility) */ + .no-more-tables thead tr { + position: absolute; + top: -9999px; + left: -9999px; + } + + .no-more-tables tr { + border: 1px solid #ccc; + } + + .no-more-tables td { + /* Behave like a "row" */ + border-top: 0 !important; + border-bottom: 1px solid #eee; + position: relative; + padding-left: 50% !important; + white-space: normal; + text-align: left; + } + + .no-more-tables td:before { + /* Now like a table header */ + position: absolute; + /* Top/left values mimic padding */ + top: 6px; + left: 6px; + width: 45%; + padding-right: 10px; + white-space: nowrap; + text-align: left; + font-weight: bold; + } + + /* + Label the data + */ + .no-more-tables td:before { + content: attr(data-title); + } +} + +/* + * Bootstrap $Panels + * + */ +.panel { + box-shadow: none; + border-radius: 2px; + +} + +.panel-form { + padding-top: 10px; +} + +.panel-heading { + border-color: #eeeff8; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.panel-heading.gray { + background: #fcfcfc; +} + +.panel-heading.gradient { + background: #fcfcfc; + background: -webkit-linear-gradient(top, #fcfcfc 0%, #f5f5f5 100%); + background: linear-gradient(to bottom, #fcfcfc 0%, #f5f5f5 100%); +} + +.panel-footer { + border-top: 1px solid #eeeff8; + background-color: #fcfcfc; +} + +.panel-group .panel { + border-radius: 2px; +} + +.panel-default { + border-color: #dcdff0; +} + +.panel-default > .panel-heading { + color: #59595a; + background-color: #eaecf6; + border-color: #dcdff0; +} + +.panel-default > .panel-heading + .panel-collapse .panel-body { + border-top-color: #dcdff0; +} + +.panel-default > .panel-heading a { + color: #59595a; +} + +.panel-default > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #dcdff0; +} + +.panel-primary { + border-color: #1582dc; +} + +.panel-primary > .panel-heading { + color: #ffffff; + background-color: #1582dc; + border-color: #1582dc; +} + +.panel-primary > .panel-heading + .panel-collapse .panel-body { + border-top-color: #1582dc; +} + +.panel-primary > .panel-heading a { + color: #ffffff; +} + +.panel-primary > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #1582dc; +} + +.panel-success { + border-color: #15db81; +} + +.panel-success > .panel-heading { + color: #ffffff; + background-color: #15db81; + border-color: #15db81; +} + +.panel-success > .panel-heading + .panel-collapse .panel-body { + border-top-color: #15db81; +} + +.panel-success > .panel-heading a { + color: #ffffff; +} + +.panel-success > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #15db81; +} + +.panel-warning { + border-color: #daac16; +} + +.panel-warning > .panel-heading { + color: #ffffff; + background-color: #daac16; + border-color: #daac16; +} + +.panel-warning > .panel-heading + .panel-collapse .panel-body { + border-top-color: #daac16; +} + +.panel-warning > .panel-heading a { + color: #ffffff; +} + +.panel-warning > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #daac16; +} + +.panel-danger { + border-color: #da3e16; +} + +.panel-danger > .panel-heading { + color: #ffffff; + background-color: #da3e16; + border-color: #da3e16; +} + +.panel-danger > .panel-heading + .panel-collapse .panel-body { + border-top-color: #da3e16; +} + +.panel-danger > .panel-heading a { + color: #ffffff; +} + +.panel-danger > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #da3e16; +} + +.panel-info { + border-color: #15acdc; +} + +.panel-info > .panel-heading { + color: #ffffff; + background-color: #15acdc; + border-color: #15acdc; +} + +.panel-info > .panel-heading + .panel-collapse .panel-body { + border-top-color: #15acdc; +} + +.panel-info > .panel-heading a { + color: #ffffff; +} + +.panel-info > .panel-footer + .panel-collapse .panel-body { + border-bottom-color: #15acdc; +} + +.heading-controls { + float: right; + display: inline-block; +} + +.heading-controls a { + border-radius: 2px; + padding: 5px; + font-size: 11px; +} + +/* + * $Forms + * + */ +/* Resize textarea vertically */ +textarea { + resize: vertical; +} + +/* Default placeholder text */ +.form-control:-moz-placeholder { + color: #a6a6a6; +} + +.form-control::-moz-placeholder { + color: #a6a6a6; +} + +.form-control:-ms-input-placeholder { + color: #a6a6a6; +} + +.form-control::-webkit-input-placeholder { + color: #a6a6a6; +} + +.placeholder { + color: #aaa; +} + +.form-control { + border: 1px solid #e3e6f3; + border-radius: 2px; + box-shadow: none; + -webkit-transition: border .25s linear, color .25s linear, background-color .25s linear; + transition: border .25s linear, color .25s linear, background-color .25s linear; + -webkit-appearance: none; + font-weight: 400; + font-size: 13px; + -webkit-font-smoothing: antialiased; +} + +.form-control:focus, +#focusedInput { + outline: 0; + border-color: #eaecf6; + background-color: #f1f2f9; + box-shadow: none; +} + +.no-resize { + resize: none; +} + +select.form-control { + -webkit-appearance: menulist; +} + +input[type="file"] { + line-height: 1; + display: none +} + +label { + font-weight: 60; +} + +label.radio, +label.checkbox { + padding-left: 20px; +} + +/* + * Validation States + * + */ +.has-success .help-block, +.has-success .control-label, +.has-success .radio, +.has-success .checkbox, +.has-success .radio-inline, +.has-success .checkbox-inline { + color: #15db81; +} + +.has-success .form-control { + border-color: #15db81; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-success .form-control:focus { + border-color: #11ac66; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #66f0b1; +} + +.has-success .input-group-addon { + color: #15db81; + border-color: #15db81; + background-color: #15db81; +} + +.has-success .form-control-feedback { + color: #15db81; +} + +.has-warning .help-block, +.has-warning .control-label, +.has-warning .radio, +.has-warning .checkbox, +.has-warning .radio-inline, +.has-warning .checkbox-inline { + color: #daac16; +} + +.has-warning .form-control { + border-color: #daac16; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-warning .form-control:focus { + border-color: #ac8711; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f0cf66; +} + +.has-warning .input-group-addon { + color: #daac16; + border-color: #daac16; + background-color: #daac16; +} + +.has-warning .form-control-feedback { + color: #daac16; +} + +.has-error .help-block, +.has-error .control-label, +.has-error .radio, +.has-error .checkbox, +.has-error .radio-inline, +.has-error .checkbox-inline { + color: #da3e16; +} + +.has-error .form-control { + border-color: #da3e16; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.has-error .form-control:focus { + border-color: #ac3111; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f08266; +} + +.has-error .input-group-addon { + color: #da3e16; + border-color: #da3e16; + background-color: #da3e16; +} + +.has-error .form-control-feedback { + color: #da3e16; +} + +.input-group-addon { + background-color: #eaecf6; + border: 1px solid #e3e6f3; + border-radius: 2px; +} + +/* + * Bootstrap $Dropdown + * + */ +.dropdown-menu { + border-radius: 2px; + border: 1px solid #dcdff0; + z-index: 9999; + box-shadow: none; +} + +.dropdown-menu > li > a { + font-size: 13px; + color: #59595a; +} + +.dropdown-menu > li > a:hover { + background: #dcdff0; +} + +.dropdown-menu .divider { + margin: 2px 0; + height: 1px; + background-color: #cacfe8; +} + +.dropdown-menu > .active > a, +.dropdown-menu > .active > a:hover, +.dropdown-menu > .active > a:focus { + background-color: #dcdff0; + color: #59595a; +} + +.dropdown.open .dropdown-menu { + display: block; +} + +@media (max-width: 767px) { + .collapse-open { + display: block; + } + + .dropdown-menu.dropdown-menu { + top: 100%; + left: 0; + } +} + +/* + * $Progress-Bar styles + * + */ +.progress { + overflow: hidden; + margin-bottom: 15px; + height: 20px; + border-radius: 2px; + background-color: #d0dbec; + box-shadow: none; +} + +.progress-bar { + box-shadow: none; + background-color: #1582dc; + -webkit-transition: width 800ms ease; + transition: width 800ms ease; +} + +.progress-bar-success { + background-color: #15db81; +} + +.progress-striped .progress-bar-success { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-info { + background-color: #15acdc; +} + +.progress-striped .progress-bar-info { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-warning { + background-color: #daac16; +} + +.progress-striped .progress-bar-warning { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +.progress-bar-danger { + background-color: #da3e16; +} + +.progress-striped .progress-bar-danger { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); +} + +/* Progress bar sizing */ +.progress-xs { + height: 5px; +} + +.progress-sm { + height: 10px; +} + +.progress-md { + height: 15px; +} + +.progress-lg { + height: 25px; +} + +/* + * Bootstrap $Buttons + * + */ +.btn { + outline: 0; + -webkit-transition: all 300ms linear; + transition: all 300ms linear; + border-radius: 2px; + padding: 9px 12px; + font-size: 13px; + -webkit-font-smoothing: antialiased; + line-height: 14px; +} + +.btn:focus, +.btn:active, +.btn.active, +.btn:active:focus, +.btn.active:focus { + outline: 0; +} + +.btn:active, +.btn.active { + box-shadow: inset 0 3px 8px rgba(0, 0, 0, 0.1); +} + +.btn-lg, +.btn-group-lg > .btn { + padding: 15px 16px; + border-radius: 4px; +} + +.btn-sm, +.btn-group-sm > .btn { + padding: 7px 10px; +} + +.btn-xs, +.btn-group-xs > .btn { + padding: 3px 5px; + font-size: 10px; +} + +/* Rounded button styles */ +.btn-rounded, +.btn-rounded a, +.btn-rounded .btn, +.input-rounded { + border-radius: 40px; +} + +/* + * Default Button Style + * + */ +.btn-default { + color: #606266; + background-color: #fff; + border: 1px solid #dcdfe6; +} + +a.btn-default { + color: #59595a; +} + +.btn-default:hover, +.btn-default:focus, +.btn-default:active, +.btn-default.active, +.open .dropdown-toggle.btn-default { + color: #59595a; + background-color: #d8dcee; + background-image: none; + border-color: #c3c8e5; +} + +.btn-default.disabled, +.btn-default[disabled], +fieldset[disabled] .btn-default, +.btn-default.disabled:hover, +.btn-default[disabled]:hover, +fieldset[disabled] .btn-default:hover, +.btn-default.disabled:focus, +.btn-default[disabled]:focus, +fieldset[disabled] .btn-default:focus, +.btn-default.disabled:active, +.btn-default[disabled]:active, +fieldset[disabled] .btn-default:active, +.btn-default.disabled.active, +.btn-default[disabled].active, +fieldset[disabled] .btn-default.active { + background-color: #eaecf6; + border-color: #d5d9ed; +} + +.btn-default.btn-outline { + background-color: transparent; + color: #eaecf6; +} + +.btn-default.btn-outline:hover, +.btn-default.btn-outline:focus, +.btn-default.btn-outline:active, +.btn-default.btn-outline.active { + background-color: #eaecf6; + color: #59595a; +} + +.btn-default.btn-outline { + color: #59595a; +} + +/* + * Primary Button Style + * + */ +.btn-primary { + color: #ffffff; + background-color: #1582dc; + border-color: #1582dc; +} + +a.btn-primary { + color: #ffffff; +} + +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: #ffffff; + background-color: #1374c5; + background-image: none; + border-color: #1374c5; +} + +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #1582dc; + border-color: #1582dc; +} + +.btn-primary.btn-outline { + background-color: transparent; + color: #1582dc; +} + +.btn-primary.btn-outline:hover, +.btn-primary.btn-outline:focus, +.btn-primary.btn-outline:active, +.btn-primary.btn-outline.active { + background-color: #1582dc; + color: #ffffff; +} + +/* + * Warning Button Style + * + */ +.btn-warning { + color: #ffffff; + background-color: #daac16; + border-color: #daac16; +} + +a.btn-warning { + color: #ffffff; +} + +.btn-warning:hover, +.btn-warning:focus, +.btn-warning:active, +.btn-warning.active, +.open .dropdown-toggle.btn-warning { + color: #ffffff; + background-color: #c39a14; + background-image: none; + border-color: #c39a14; +} + +.btn-warning.disabled, +.btn-warning[disabled], +fieldset[disabled] .btn-warning, +.btn-warning.disabled:hover, +.btn-warning[disabled]:hover, +fieldset[disabled] .btn-warning:hover, +.btn-warning.disabled:focus, +.btn-warning[disabled]:focus, +fieldset[disabled] .btn-warning:focus, +.btn-warning.disabled:active, +.btn-warning[disabled]:active, +fieldset[disabled] .btn-warning:active, +.btn-warning.disabled.active, +.btn-warning[disabled].active, +fieldset[disabled] .btn-warning.active { + background-color: #daac16; + border-color: #daac16; +} + +.btn-warning.btn-outline { + background-color: transparent; + color: #daac16; +} + +.btn-warning.btn-outline:hover, +.btn-warning.btn-outline:focus, +.btn-warning.btn-outline:active, +.btn-warning.btn-outline.active { + background-color: #daac16; + color: #ffffff; +} + +/* + * Success Button Style + * + */ +.btn-success { + color: #ffffff; + background-color: #15db81; + border-color: #15db81; +} + +a.btn-success { + color: #ffffff; +} + +.btn-success:hover, +.btn-success:focus, +.btn-success:active, +.btn-success.active, +.open .dropdown-toggle.btn-success { + color: #ffffff; + background-color: #13c473; + background-image: none; + border-color: #13c473; +} + +.btn-success.disabled, +.btn-success[disabled], +fieldset[disabled] .btn-success, +.btn-success.disabled:hover, +.btn-success[disabled]:hover, +fieldset[disabled] .btn-success:hover, +.btn-success.disabled:focus, +.btn-success[disabled]:focus, +fieldset[disabled] .btn-success:focus, +.btn-success.disabled:active, +.btn-success[disabled]:active, +fieldset[disabled] .btn-success:active, +.btn-success.disabled.active, +.btn-success[disabled].active, +fieldset[disabled] .btn-success.active { + background-color: #15db81; + border-color: #15db81; +} + +.btn-success.btn-outline { + background-color: transparent; + color: #15db81; +} + +.btn-success.btn-outline:hover, +.btn-success.btn-outline:focus, +.btn-success.btn-outline:active, +.btn-success.btn-outline.active { + background-color: #15db81; + color: #ffffff; +} + +/* + * Info Button Style + * + */ +.btn-info { + color: #ffffff; + background-color: #15acdc; + border-color: #15acdc; +} + +a.btn-info { + color: #ffffff; +} + +.btn-info:hover, +.btn-info:focus, +.btn-info:active, +.btn-info.active, +.open .dropdown-toggle.btn-info { + color: #ffffff; + background-color: #139ac5; + background-image: none; + border-color: #139ac5; +} + +.btn-info.disabled, +.btn-info[disabled], +fieldset[disabled] .btn-info, +.btn-info.disabled:hover, +.btn-info[disabled]:hover, +fieldset[disabled] .btn-info:hover, +.btn-info.disabled:focus, +.btn-info[disabled]:focus, +fieldset[disabled] .btn-info:focus, +.btn-info.disabled:active, +.btn-info[disabled]:active, +fieldset[disabled] .btn-info:active, +.btn-info.disabled.active, +.btn-info[disabled].active, +fieldset[disabled] .btn-info.active { + background-color: #15acdc; + border-color: #15acdc; +} + +.btn-info.btn-outline { + background-color: transparent; + color: #15acdc; +} + +.btn-info.btn-outline:hover, +.btn-info.btn-outline:focus, +.btn-info.btn-outline:active, +.btn-info.btn-outline.active { + background-color: #15acdc; + color: #ffffff; +} + +/* + * Danger Button Style + * + */ +.btn-danger { + color: #ffffff; + background-color: #da3e16; + border-color: #da3e16; +} + +a.btn-danger { + color: #ffffff; +} + +.btn-danger:hover, +.btn-danger:focus, +.btn-danger:active, +.btn-danger.active, +.open .dropdown-toggle.btn-danger { + color: #ffffff; + background-color: #c33714; + background-image: none; + border-color: #c33714; +} + +.btn-danger.disabled, +.btn-danger[disabled], +fieldset[disabled] .btn-danger, +.btn-danger.disabled:hover, +.btn-danger[disabled]:hover, +fieldset[disabled] .btn-danger:hover, +.btn-danger.disabled:focus, +.btn-danger[disabled]:focus, +fieldset[disabled] .btn-danger:focus, +.btn-danger.disabled:active, +.btn-danger[disabled]:active, +fieldset[disabled] .btn-danger:active, +.btn-danger.disabled.active, +.btn-danger[disabled].active, +fieldset[disabled] .btn-danger.active { + background-color: #da3e16; + border-color: #da3e16; +} + +.btn-danger.btn-outline { + background-color: transparent; + color: #da3e16; +} + +.btn-danger.btn-outline:hover, +.btn-danger.btn-outline:focus, +.btn-danger.btn-outline:active, +.btn-danger.btn-outline.active { + background-color: #da3e16; + color: #ffffff; +} + +/* + * Social Buttons for Bootstrap + * + * Copyright 2013-2014 Panayiotis Lipiridis + * Licensed under the MIT License + * + * https://github.com/lipis/bootstrap-social + */ +.btn-social { + position: relative; + padding-left: 47px; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.btn-social :first-child { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 32px; + line-height: 34px; + font-size: 1.6em; + text-align: center; + border-right: 1px solid rgba(0, 0, 0, 0.1); +} + +.btn-social.btn-lg { + padding-left: 62px; +} + +.btn-social.btn-lg :first-child { + line-height: 46px; + width: 46px; + font-size: 1.8em; +} + +.btn-social.btn-sm { + padding-left: 37px; +} + +.btn-social.btn-sm :first-child { + line-height: 27px; + width: 27px; + font-size: 1.4em; +} + +.btn-social.btn-xs { + padding-left: 30px; +} + +.btn-social.btn-xs :first-child { + line-height: 20px; + width: 20px; + font-size: 1.2em; +} + +.btn-social-icon { + position: relative; + padding-left: 47px; + text-align: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + height: 34px; + width: 34px; + padding: 0; +} + +.btn-social-icon :first-child { + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 32px; + line-height: 34px; + font-size: 1.6em; + text-align: center; + border-right: 1px solid rgba(0, 0, 0, 0.1); +} + +.btn-social-icon.btn-lg { + padding-left: 62px; +} + +.btn-social-icon.btn-lg :first-child { + line-height: 46px; + width: 46px; + font-size: 1.8em; +} + +.btn-social-icon.btn-sm { + padding-left: 37px; +} + +.btn-social-icon.btn-sm :first-child { + line-height: 27px; + width: 27px; + font-size: 1.4em; +} + +.btn-social-icon.btn-xs { + padding-left: 30px; +} + +.btn-social-icon.btn-xs :first-child { + line-height: 20px; + width: 20px; + font-size: 1.2em; +} + +.btn-social-icon :first-child { + border: none; + text-align: center; + width: 100% !important; +} + +.btn-social-icon.btn-lg { + height: 46px; + width: 46px; + padding-left: 0; + padding-right: 0; +} + +.btn-social-icon.btn-sm { + height: 29px; + width: 29px; + padding-left: 0; + padding-right: 0; +} + +.btn-social-icon.btn-xs { + height: 22px; + width: 22px; + padding-left: 0; + padding-right: 0; +} + +.btn-adn { + color: #ffffff; + background-color: #d87a68; + border-color: #d87a68; +} + +a.btn-adn { + color: #ffffff; +} + +.btn-adn:hover, +.btn-adn:focus, +.btn-adn:active, +.btn-adn.active, +.open .dropdown-toggle.btn-adn { + color: #ffffff; + background-color: #d36854; + background-image: none; + border-color: #d36854; +} + +.btn-adn.disabled, +.btn-adn[disabled], +fieldset[disabled] .btn-adn, +.btn-adn.disabled:hover, +.btn-adn[disabled]:hover, +fieldset[disabled] .btn-adn:hover, +.btn-adn.disabled:focus, +.btn-adn[disabled]:focus, +fieldset[disabled] .btn-adn:focus, +.btn-adn.disabled:active, +.btn-adn[disabled]:active, +fieldset[disabled] .btn-adn:active, +.btn-adn.disabled.active, +.btn-adn[disabled].active, +fieldset[disabled] .btn-adn.active { + background-color: #d87a68; + border-color: #d87a68; +} + +.btn-adn.btn-outline { + background-color: transparent; + color: #d87a68; +} + +.btn-adn.btn-outline:hover, +.btn-adn.btn-outline:focus, +.btn-adn.btn-outline:active, +.btn-adn.btn-outline.active { + background-color: #d87a68; + color: #ffffff; +} + +.btn-bitbucket { + color: #ffffff; + background-color: #205081; + border-color: #205081; +} + +a.btn-bitbucket { + color: #ffffff; +} + +.btn-bitbucket:hover, +.btn-bitbucket:focus, +.btn-bitbucket:active, +.btn-bitbucket.active, +.open .dropdown-toggle.btn-bitbucket { + color: #ffffff; + background-color: #1b436d; + background-image: none; + border-color: #1b436d; +} + +.btn-bitbucket.disabled, +.btn-bitbucket[disabled], +fieldset[disabled] .btn-bitbucket, +.btn-bitbucket.disabled:hover, +.btn-bitbucket[disabled]:hover, +fieldset[disabled] .btn-bitbucket:hover, +.btn-bitbucket.disabled:focus, +.btn-bitbucket[disabled]:focus, +fieldset[disabled] .btn-bitbucket:focus, +.btn-bitbucket.disabled:active, +.btn-bitbucket[disabled]:active, +fieldset[disabled] .btn-bitbucket:active, +.btn-bitbucket.disabled.active, +.btn-bitbucket[disabled].active, +fieldset[disabled] .btn-bitbucket.active { + background-color: #205081; + border-color: #205081; +} + +.btn-bitbucket.btn-outline { + background-color: transparent; + color: #205081; +} + +.btn-bitbucket.btn-outline:hover, +.btn-bitbucket.btn-outline:focus, +.btn-bitbucket.btn-outline:active, +.btn-bitbucket.btn-outline.active { + background-color: #205081; + color: #ffffff; +} + +.btn-dropbox { + color: #ffffff; + background-color: #1087dd; + border-color: #1087dd; +} + +a.btn-dropbox { + color: #ffffff; +} + +.btn-dropbox:hover, +.btn-dropbox:focus, +.btn-dropbox:active, +.btn-dropbox.active, +.open .dropdown-toggle.btn-dropbox { + color: #ffffff; + background-color: #0e78c5; + background-image: none; + border-color: #0e78c5; +} + +.btn-dropbox.disabled, +.btn-dropbox[disabled], +fieldset[disabled] .btn-dropbox, +.btn-dropbox.disabled:hover, +.btn-dropbox[disabled]:hover, +fieldset[disabled] .btn-dropbox:hover, +.btn-dropbox.disabled:focus, +.btn-dropbox[disabled]:focus, +fieldset[disabled] .btn-dropbox:focus, +.btn-dropbox.disabled:active, +.btn-dropbox[disabled]:active, +fieldset[disabled] .btn-dropbox:active, +.btn-dropbox.disabled.active, +.btn-dropbox[disabled].active, +fieldset[disabled] .btn-dropbox.active { + background-color: #1087dd; + border-color: #1087dd; +} + +.btn-dropbox.btn-outline { + background-color: transparent; + color: #1087dd; +} + +.btn-dropbox.btn-outline:hover, +.btn-dropbox.btn-outline:focus, +.btn-dropbox.btn-outline:active, +.btn-dropbox.btn-outline.active { + background-color: #1087dd; + color: #ffffff; +} + +.btn-facebook { + color: #ffffff; + background-color: #3b5998; + border-color: #3b5998; +} + +a.btn-facebook { + color: #ffffff; +} + +.btn-facebook:hover, +.btn-facebook:focus, +.btn-facebook:active, +.btn-facebook.active, +.open .dropdown-toggle.btn-facebook { + color: #ffffff; + background-color: #344e86; + background-image: none; + border-color: #344e86; +} + +.btn-facebook.disabled, +.btn-facebook[disabled], +fieldset[disabled] .btn-facebook, +.btn-facebook.disabled:hover, +.btn-facebook[disabled]:hover, +fieldset[disabled] .btn-facebook:hover, +.btn-facebook.disabled:focus, +.btn-facebook[disabled]:focus, +fieldset[disabled] .btn-facebook:focus, +.btn-facebook.disabled:active, +.btn-facebook[disabled]:active, +fieldset[disabled] .btn-facebook:active, +.btn-facebook.disabled.active, +.btn-facebook[disabled].active, +fieldset[disabled] .btn-facebook.active { + background-color: #3b5998; + border-color: #3b5998; +} + +.btn-facebook.btn-outline { + background-color: transparent; + color: #3b5998; +} + +.btn-facebook.btn-outline:hover, +.btn-facebook.btn-outline:focus, +.btn-facebook.btn-outline:active, +.btn-facebook.btn-outline.active { + background-color: #3b5998; + color: #ffffff; +} + +.btn-flickr { + color: #ffffff; + background-color: #ff0084; + border-color: #ff0084; +} + +a.btn-flickr { + color: #ffffff; +} + +.btn-flickr:hover, +.btn-flickr:focus, +.btn-flickr:active, +.btn-flickr.active, +.open .dropdown-toggle.btn-flickr { + color: #ffffff; + background-color: #e60077; + background-image: none; + border-color: #e60077; +} + +.btn-flickr.disabled, +.btn-flickr[disabled], +fieldset[disabled] .btn-flickr, +.btn-flickr.disabled:hover, +.btn-flickr[disabled]:hover, +fieldset[disabled] .btn-flickr:hover, +.btn-flickr.disabled:focus, +.btn-flickr[disabled]:focus, +fieldset[disabled] .btn-flickr:focus, +.btn-flickr.disabled:active, +.btn-flickr[disabled]:active, +fieldset[disabled] .btn-flickr:active, +.btn-flickr.disabled.active, +.btn-flickr[disabled].active, +fieldset[disabled] .btn-flickr.active { + background-color: #ff0084; + border-color: #ff0084; +} + +.btn-flickr.btn-outline { + background-color: transparent; + color: #ff0084; +} + +.btn-flickr.btn-outline:hover, +.btn-flickr.btn-outline:focus, +.btn-flickr.btn-outline:active, +.btn-flickr.btn-outline.active { + background-color: #ff0084; + color: #ffffff; +} + +.btn-foursquare { + color: #ffffff; + background-color: #0072b1; + border-color: #0072b1; +} + +a.btn-foursquare { + color: #ffffff; +} + +.btn-foursquare:hover, +.btn-foursquare:focus, +.btn-foursquare:active, +.btn-foursquare.active, +.open .dropdown-toggle.btn-foursquare { + color: #ffffff; + background-color: #006298; + background-image: none; + border-color: #006298; +} + +.btn-foursquare.disabled, +.btn-foursquare[disabled], +fieldset[disabled] .btn-foursquare, +.btn-foursquare.disabled:hover, +.btn-foursquare[disabled]:hover, +fieldset[disabled] .btn-foursquare:hover, +.btn-foursquare.disabled:focus, +.btn-foursquare[disabled]:focus, +fieldset[disabled] .btn-foursquare:focus, +.btn-foursquare.disabled:active, +.btn-foursquare[disabled]:active, +fieldset[disabled] .btn-foursquare:active, +.btn-foursquare.disabled.active, +.btn-foursquare[disabled].active, +fieldset[disabled] .btn-foursquare.active { + background-color: #0072b1; + border-color: #0072b1; +} + +.btn-foursquare.btn-outline { + background-color: transparent; + color: #0072b1; +} + +.btn-foursquare.btn-outline:hover, +.btn-foursquare.btn-outline:focus, +.btn-foursquare.btn-outline:active, +.btn-foursquare.btn-outline.active { + background-color: #0072b1; + color: #ffffff; +} + +.btn-github { + color: #ffffff; + background-color: #444444; + border-color: #444444; +} + +a.btn-github { + color: #ffffff; +} + +.btn-github:hover, +.btn-github:focus, +.btn-github:active, +.btn-github.active, +.open .dropdown-toggle.btn-github { + color: #ffffff; + background-color: #373737; + background-image: none; + border-color: #373737; +} + +.btn-github.disabled, +.btn-github[disabled], +fieldset[disabled] .btn-github, +.btn-github.disabled:hover, +.btn-github[disabled]:hover, +fieldset[disabled] .btn-github:hover, +.btn-github.disabled:focus, +.btn-github[disabled]:focus, +fieldset[disabled] .btn-github:focus, +.btn-github.disabled:active, +.btn-github[disabled]:active, +fieldset[disabled] .btn-github:active, +.btn-github.disabled.active, +.btn-github[disabled].active, +fieldset[disabled] .btn-github.active { + background-color: #444444; + border-color: #444444; +} + +.btn-github.btn-outline { + background-color: transparent; + color: #444444; +} + +.btn-github.btn-outline:hover, +.btn-github.btn-outline:focus, +.btn-github.btn-outline:active, +.btn-github.btn-outline.active { + background-color: #444444; + color: #ffffff; +} + +.btn-google-plus { + color: #ffffff; + background-color: #dd4b39; + border-color: #dd4b39; +} + +a.btn-google-plus { + color: #ffffff; +} + +.btn-google-plus:hover, +.btn-google-plus:focus, +.btn-google-plus:active, +.btn-google-plus.active, +.open .dropdown-toggle.btn-google-plus { + color: #ffffff; + background-color: #d73925; + background-image: none; + border-color: #d73925; +} + +.btn-google-plus.disabled, +.btn-google-plus[disabled], +fieldset[disabled] .btn-google-plus, +.btn-google-plus.disabled:hover, +.btn-google-plus[disabled]:hover, +fieldset[disabled] .btn-google-plus:hover, +.btn-google-plus.disabled:focus, +.btn-google-plus[disabled]:focus, +fieldset[disabled] .btn-google-plus:focus, +.btn-google-plus.disabled:active, +.btn-google-plus[disabled]:active, +fieldset[disabled] .btn-google-plus:active, +.btn-google-plus.disabled.active, +.btn-google-plus[disabled].active, +fieldset[disabled] .btn-google-plus.active { + background-color: #dd4b39; + border-color: #dd4b39; +} + +.btn-google-plus.btn-outline { + background-color: transparent; + color: #dd4b39; +} + +.btn-google-plus.btn-outline:hover, +.btn-google-plus.btn-outline:focus, +.btn-google-plus.btn-outline:active, +.btn-google-plus.btn-outline.active { + background-color: #dd4b39; + color: #ffffff; +} + +.btn-instagram { + color: #ffffff; + background-color: #3f729b; + border-color: #3f729b; +} + +a.btn-instagram { + color: #ffffff; +} + +.btn-instagram:hover, +.btn-instagram:focus, +.btn-instagram:active, +.btn-instagram.active, +.open .dropdown-toggle.btn-instagram { + color: #ffffff; + background-color: #386589; + background-image: none; + border-color: #386589; +} + +.btn-instagram.disabled, +.btn-instagram[disabled], +fieldset[disabled] .btn-instagram, +.btn-instagram.disabled:hover, +.btn-instagram[disabled]:hover, +fieldset[disabled] .btn-instagram:hover, +.btn-instagram.disabled:focus, +.btn-instagram[disabled]:focus, +fieldset[disabled] .btn-instagram:focus, +.btn-instagram.disabled:active, +.btn-instagram[disabled]:active, +fieldset[disabled] .btn-instagram:active, +.btn-instagram.disabled.active, +.btn-instagram[disabled].active, +fieldset[disabled] .btn-instagram.active { + background-color: #3f729b; + border-color: #3f729b; +} + +.btn-instagram.btn-outline { + background-color: transparent; + color: #3f729b; +} + +.btn-instagram.btn-outline:hover, +.btn-instagram.btn-outline:focus, +.btn-instagram.btn-outline:active, +.btn-instagram.btn-outline.active { + background-color: #3f729b; + color: #ffffff; +} + +.btn-linkedin { + color: #ffffff; + background-color: #007bb6; + border-color: #007bb6; +} + +a.btn-linkedin { + color: #ffffff; +} + +.btn-linkedin:hover, +.btn-linkedin:focus, +.btn-linkedin:active, +.btn-linkedin.active, +.open .dropdown-toggle.btn-linkedin { + color: #ffffff; + background-color: #006a9d; + background-image: none; + border-color: #006a9d; +} + +.btn-linkedin.disabled, +.btn-linkedin[disabled], +fieldset[disabled] .btn-linkedin, +.btn-linkedin.disabled:hover, +.btn-linkedin[disabled]:hover, +fieldset[disabled] .btn-linkedin:hover, +.btn-linkedin.disabled:focus, +.btn-linkedin[disabled]:focus, +fieldset[disabled] .btn-linkedin:focus, +.btn-linkedin.disabled:active, +.btn-linkedin[disabled]:active, +fieldset[disabled] .btn-linkedin:active, +.btn-linkedin.disabled.active, +.btn-linkedin[disabled].active, +fieldset[disabled] .btn-linkedin.active { + background-color: #007bb6; + border-color: #007bb6; +} + +.btn-linkedin.btn-outline { + background-color: transparent; + color: #007bb6; +} + +.btn-linkedin.btn-outline:hover, +.btn-linkedin.btn-outline:focus, +.btn-linkedin.btn-outline:active, +.btn-linkedin.btn-outline.active { + background-color: #007bb6; + color: #ffffff; +} + +.btn-microsoft { + color: #ffffff; + background-color: #2672ec; + border-color: #2672ec; +} + +a.btn-microsoft { + color: #ffffff; +} + +.btn-microsoft:hover, +.btn-microsoft:focus, +.btn-microsoft:active, +.btn-microsoft.active, +.open .dropdown-toggle.btn-microsoft { + color: #ffffff; + background-color: #1464e4; + background-image: none; + border-color: #1464e4; +} + +.btn-microsoft.disabled, +.btn-microsoft[disabled], +fieldset[disabled] .btn-microsoft, +.btn-microsoft.disabled:hover, +.btn-microsoft[disabled]:hover, +fieldset[disabled] .btn-microsoft:hover, +.btn-microsoft.disabled:focus, +.btn-microsoft[disabled]:focus, +fieldset[disabled] .btn-microsoft:focus, +.btn-microsoft.disabled:active, +.btn-microsoft[disabled]:active, +fieldset[disabled] .btn-microsoft:active, +.btn-microsoft.disabled.active, +.btn-microsoft[disabled].active, +fieldset[disabled] .btn-microsoft.active { + background-color: #2672ec; + border-color: #2672ec; +} + +.btn-microsoft.btn-outline { + background-color: transparent; + color: #2672ec; +} + +.btn-microsoft.btn-outline:hover, +.btn-microsoft.btn-outline:focus, +.btn-microsoft.btn-outline:active, +.btn-microsoft.btn-outline.active { + background-color: #2672ec; + color: #ffffff; +} + +.btn-openid { + color: #ffffff; + background-color: #f7931e; + border-color: #f7931e; +} + +a.btn-openid { + color: #ffffff; +} + +.btn-openid:hover, +.btn-openid:focus, +.btn-openid:active, +.btn-openid.active, +.open .dropdown-toggle.btn-openid { + color: #ffffff; + background-color: #f38709; + background-image: none; + border-color: #f38709; +} + +.btn-openid.disabled, +.btn-openid[disabled], +fieldset[disabled] .btn-openid, +.btn-openid.disabled:hover, +.btn-openid[disabled]:hover, +fieldset[disabled] .btn-openid:hover, +.btn-openid.disabled:focus, +.btn-openid[disabled]:focus, +fieldset[disabled] .btn-openid:focus, +.btn-openid.disabled:active, +.btn-openid[disabled]:active, +fieldset[disabled] .btn-openid:active, +.btn-openid.disabled.active, +.btn-openid[disabled].active, +fieldset[disabled] .btn-openid.active { + background-color: #f7931e; + border-color: #f7931e; +} + +.btn-openid.btn-outline { + background-color: transparent; + color: #f7931e; +} + +.btn-openid.btn-outline:hover, +.btn-openid.btn-outline:focus, +.btn-openid.btn-outline:active, +.btn-openid.btn-outline.active { + background-color: #f7931e; + color: #ffffff; +} + +.btn-reddit { + color: #000000; + background-color: #eff7ff; + border-color: #eff7ff; +} + +a.btn-reddit { + color: #000000; +} + +.btn-reddit:hover, +.btn-reddit:focus, +.btn-reddit:active, +.btn-reddit.active, +.open .dropdown-toggle.btn-reddit { + color: #000000; + background-color: #d6eaff; + background-image: none; + border-color: #d6eaff; +} + +.btn-reddit.disabled, +.btn-reddit[disabled], +fieldset[disabled] .btn-reddit, +.btn-reddit.disabled:hover, +.btn-reddit[disabled]:hover, +fieldset[disabled] .btn-reddit:hover, +.btn-reddit.disabled:focus, +.btn-reddit[disabled]:focus, +fieldset[disabled] .btn-reddit:focus, +.btn-reddit.disabled:active, +.btn-reddit[disabled]:active, +fieldset[disabled] .btn-reddit:active, +.btn-reddit.disabled.active, +.btn-reddit[disabled].active, +fieldset[disabled] .btn-reddit.active { + background-color: #eff7ff; + border-color: #eff7ff; +} + +.btn-reddit.btn-outline { + background-color: transparent; + color: #eff7ff; +} + +.btn-reddit.btn-outline:hover, +.btn-reddit.btn-outline:focus, +.btn-reddit.btn-outline:active, +.btn-reddit.btn-outline.active { + background-color: #eff7ff; + color: #000000; +} + +.btn-soundcloud { + color: #ffffff; + background-color: #ff5500; + border-color: #ff5500; +} + +a.btn-soundcloud { + color: #ffffff; +} + +.btn-soundcloud:hover, +.btn-soundcloud:focus, +.btn-soundcloud:active, +.btn-soundcloud.active, +.open .dropdown-toggle.btn-soundcloud { + color: #ffffff; + background-color: #e64d00; + background-image: none; + border-color: #e64d00; +} + +.btn-soundcloud.disabled, +.btn-soundcloud[disabled], +fieldset[disabled] .btn-soundcloud, +.btn-soundcloud.disabled:hover, +.btn-soundcloud[disabled]:hover, +fieldset[disabled] .btn-soundcloud:hover, +.btn-soundcloud.disabled:focus, +.btn-soundcloud[disabled]:focus, +fieldset[disabled] .btn-soundcloud:focus, +.btn-soundcloud.disabled:active, +.btn-soundcloud[disabled]:active, +fieldset[disabled] .btn-soundcloud:active, +.btn-soundcloud.disabled.active, +.btn-soundcloud[disabled].active, +fieldset[disabled] .btn-soundcloud.active { + background-color: #ff5500; + border-color: #ff5500; +} + +.btn-soundcloud.btn-outline { + background-color: transparent; + color: #ff5500; +} + +.btn-soundcloud.btn-outline:hover, +.btn-soundcloud.btn-outline:focus, +.btn-soundcloud.btn-outline:active, +.btn-soundcloud.btn-outline.active { + background-color: #ff5500; + color: #ffffff; +} + +.btn-tumblr { + color: #ffffff; + background-color: #2c4762; + border-color: #2c4762; +} + +a.btn-tumblr { + color: #ffffff; +} + +.btn-tumblr:hover, +.btn-tumblr:focus, +.btn-tumblr:active, +.btn-tumblr.active, +.open .dropdown-toggle.btn-tumblr { + color: #ffffff; + background-color: #243a50; + background-image: none; + border-color: #243a50; +} + +.btn-tumblr.disabled, +.btn-tumblr[disabled], +fieldset[disabled] .btn-tumblr, +.btn-tumblr.disabled:hover, +.btn-tumblr[disabled]:hover, +fieldset[disabled] .btn-tumblr:hover, +.btn-tumblr.disabled:focus, +.btn-tumblr[disabled]:focus, +fieldset[disabled] .btn-tumblr:focus, +.btn-tumblr.disabled:active, +.btn-tumblr[disabled]:active, +fieldset[disabled] .btn-tumblr:active, +.btn-tumblr.disabled.active, +.btn-tumblr[disabled].active, +fieldset[disabled] .btn-tumblr.active { + background-color: #2c4762; + border-color: #2c4762; +} + +.btn-tumblr.btn-outline { + background-color: transparent; + color: #2c4762; +} + +.btn-tumblr.btn-outline:hover, +.btn-tumblr.btn-outline:focus, +.btn-tumblr.btn-outline:active, +.btn-tumblr.btn-outline.active { + background-color: #2c4762; + color: #ffffff; +} + +.btn-twitter { + color: #ffffff; + background-color: #55acee; + border-color: #55acee; +} + +a.btn-twitter { + color: #ffffff; +} + +.btn-twitter:hover, +.btn-twitter:focus, +.btn-twitter:active, +.btn-twitter.active, +.open .dropdown-toggle.btn-twitter { + color: #ffffff; + background-color: #3ea1ec; + background-image: none; + border-color: #3ea1ec; +} + +.btn-twitter.disabled, +.btn-twitter[disabled], +fieldset[disabled] .btn-twitter, +.btn-twitter.disabled:hover, +.btn-twitter[disabled]:hover, +fieldset[disabled] .btn-twitter:hover, +.btn-twitter.disabled:focus, +.btn-twitter[disabled]:focus, +fieldset[disabled] .btn-twitter:focus, +.btn-twitter.disabled:active, +.btn-twitter[disabled]:active, +fieldset[disabled] .btn-twitter:active, +.btn-twitter.disabled.active, +.btn-twitter[disabled].active, +fieldset[disabled] .btn-twitter.active { + background-color: #55acee; + border-color: #55acee; +} + +.btn-twitter.btn-outline { + background-color: transparent; + color: #55acee; +} + +.btn-twitter.btn-outline:hover, +.btn-twitter.btn-outline:focus, +.btn-twitter.btn-outline:active, +.btn-twitter.btn-outline.active { + background-color: #55acee; + color: #ffffff; +} + +.btn-vimeo { + color: #ffffff; + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +a.btn-vimeo { + color: #ffffff; +} + +.btn-vimeo:hover, +.btn-vimeo:focus, +.btn-vimeo:active, +.btn-vimeo.active, +.open .dropdown-toggle.btn-vimeo { + color: #ffffff; + background-color: #14a7d7; + background-image: none; + border-color: #14a7d7; +} + +.btn-vimeo.disabled, +.btn-vimeo[disabled], +fieldset[disabled] .btn-vimeo, +.btn-vimeo.disabled:hover, +.btn-vimeo[disabled]:hover, +fieldset[disabled] .btn-vimeo:hover, +.btn-vimeo.disabled:focus, +.btn-vimeo[disabled]:focus, +fieldset[disabled] .btn-vimeo:focus, +.btn-vimeo.disabled:active, +.btn-vimeo[disabled]:active, +fieldset[disabled] .btn-vimeo:active, +.btn-vimeo.disabled.active, +.btn-vimeo[disabled].active, +fieldset[disabled] .btn-vimeo.active { + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +.btn-vimeo.btn-outline { + background-color: transparent; + color: #1ab7ea; +} + +.btn-vimeo.btn-outline:hover, +.btn-vimeo.btn-outline:focus, +.btn-vimeo.btn-outline:active, +.btn-vimeo.btn-outline.active { + background-color: #1ab7ea; + color: #ffffff; +} + +.btn-vk { + color: #ffffff; + background-color: #587ea3; + border-color: #587ea3; +} + +a.btn-vk { + color: #ffffff; +} + +.btn-vk:hover, +.btn-vk:focus, +.btn-vk:active, +.btn-vk.active, +.open .dropdown-toggle.btn-vk { + color: #ffffff; + background-color: #4f7192; + background-image: none; + border-color: #4f7192; +} + +.btn-vk.disabled, +.btn-vk[disabled], +fieldset[disabled] .btn-vk, +.btn-vk.disabled:hover, +.btn-vk[disabled]:hover, +fieldset[disabled] .btn-vk:hover, +.btn-vk.disabled:focus, +.btn-vk[disabled]:focus, +fieldset[disabled] .btn-vk:focus, +.btn-vk.disabled:active, +.btn-vk[disabled]:active, +fieldset[disabled] .btn-vk:active, +.btn-vk.disabled.active, +.btn-vk[disabled].active, +fieldset[disabled] .btn-vk.active { + background-color: #587ea3; + border-color: #587ea3; +} + +.btn-vk.btn-outline { + background-color: transparent; + color: #587ea3; +} + +.btn-vk.btn-outline:hover, +.btn-vk.btn-outline:focus, +.btn-vk.btn-outline:active, +.btn-vk.btn-outline.active { + background-color: #587ea3; + color: #ffffff; +} + +.btn-yahoo { + color: #ffffff; + background-color: #720e9e; + border-color: #720e9e; +} + +a.btn-yahoo { + color: #ffffff; +} + +.btn-yahoo:hover, +.btn-yahoo:focus, +.btn-yahoo:active, +.btn-yahoo.active, +.open .dropdown-toggle.btn-yahoo { + color: #ffffff; + background-color: #610c87; + background-image: none; + border-color: #610c87; +} + +.btn-yahoo.disabled, +.btn-yahoo[disabled], +fieldset[disabled] .btn-yahoo, +.btn-yahoo.disabled:hover, +.btn-yahoo[disabled]:hover, +fieldset[disabled] .btn-yahoo:hover, +.btn-yahoo.disabled:focus, +.btn-yahoo[disabled]:focus, +fieldset[disabled] .btn-yahoo:focus, +.btn-yahoo.disabled:active, +.btn-yahoo[disabled]:active, +fieldset[disabled] .btn-yahoo:active, +.btn-yahoo.disabled.active, +.btn-yahoo[disabled].active, +fieldset[disabled] .btn-yahoo.active { + background-color: #720e9e; + border-color: #720e9e; +} + +.btn-yahoo.btn-outline { + background-color: transparent; + color: #720e9e; +} + +.btn-yahoo.btn-outline:hover, +.btn-yahoo.btn-outline:focus, +.btn-yahoo.btn-outline:active, +.btn-yahoo.btn-outline.active { + background-color: #720e9e; + color: #ffffff; +} + +/* + * $Navbar + * + */ +.navbar .navbar-text { + float: left; + margin-right: 15px; + margin-left: 15px; +} + +.navbar-nav.nav-tabs { + background: transparent; + border-radius: 0; +} + +.navbar-nav.nav-tabs > li > a { + margin: 0; + border-radius: 0; + padding: 16px 15px; +} + +.navbar-inverse { + border-color: #4f5061; + background-color: #4f5061; +} + +.navbar-inverse .navbar-brand, +.navbar-inverse .navbar-nav > li > a { + color: #ffffff; +} + +.navbar-inverse .navbar-nav > .open > a, +.navbar-inverse .navbar-nav > .open > a:hover, +.navbar-inverse .navbar-nav > .open > a:focus, +.navbar-inverse .navbar-nav > .active > a, +.navbar-inverse .navbar-nav > .active > a:hover, +.navbar-inverse .navbar-nav > .active > a:focus { + color: #fff; + background-color: #484959; +} + +.navbar-inverse .navbar-collapse, +.navbar-inverse .navbar-form { + border-color: #4f5061; +} + +.navbar-inverse .navbar-nav .open .dropdown-menu .divider { + background-color: #444453; +} + +.navbar-inverse .dropdown-menu { + border-color: #4f5061; +} + +@media (max-width: 767px) { + .navbar-collapse { + padding: 0; + } + + .navbar-inverse .navbar-nav .open .dropdown-menu > li > a { + color: #ffffff; + } +} + +@media (max-width: 767px) { + .navbar-form { + padding-top: 0; + padding-bottom: 0; + } +} + +/* + * Bootstrap $Navs + * + */ +/* Pills */ +.nav-pills > li.active > a, +.nav-pills > li.active > a:hover, +.nav-pills > li.active > a:focus { + color: #fff; + background-color: #1582dc; +} + +.nav-pills > li > a { + border-radius: 2px; +} + +/* Tabs */ +.nav-tabs { + border-bottom: 0; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + background: #eaecf6; +} + +.nav-tabs > li { + margin: 0; +} + +.nav-tabs > li > a { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border: 1px solid transparent; + border-bottom: 0; + margin-left: 1px; +} + +.nav-tabs > li.active > a, +.nav-tabs > li.active > a:hover, +.nav-tabs > li.active > a:focus { + color: #59595a; + border: 1px solid #fff; + border-bottom: 0; +} + +.nav-tabs > li > a:hover, +.nav-tabs > li > a:hover, +.nav-tabs > li > a:focus { + background-color: transparent; + border-color: transparent; + color: #383839; +} + +.tabs-left .nav-tabs { + float: left; + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 0; +} + +.tabs-left .nav-tabs > li { + float: none; +} + +.tabs-left .nav-tabs > li > a { + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 0; + margin-right: 0; + margin-bottom: 2px; + margin-left: 0; +} + +.tabs-left .nav-tabs > li.active > a, +.tabs-left .nav-tabs > li.active > a:hover, +.tabs-left .nav-tabs > li.active > a:focus { + color: #59595a; +} + +.tabs-right .nav-tabs { + float: right; + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 2px; +} + +.tabs-right .nav-tabs > li { + float: none; +} + +.tabs-right .nav-tabs > li > a { + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 2px; + margin-right: 0; + margin-bottom: 2px; + margin-left: 0; +} + +.tabs-right .nav-tabs > li.active > a, +.tabs-right .nav-tabs > li.active > a:hover, +.tabs-right .nav-tabs > li.active > a:focus { + color: #59595a; +} + +.box-tab { + margin-bottom: 25px; + border: 1px solid #e3e6f3; + border-radius: 2px; +} + +.box-tab .tab-content { + background-color: #fff; + padding: 15px; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); + border-top-left-radius: 0; + border-top-right-radius: 0; + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + overflow: hidden; +} + +.box-tab.tabs-left .tab-content { + border-top-left-radius: 0; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 2px; +} + +.box-tab.tabs-right .tab-content { + border-top-left-radius: 2px; + border-top-right-radius: 0; + border-bottom-left-radius: 0; + border-bottom-right-radius: 2px; +} + +/* + * $Labels + * + */ +.label { + line-height: inherit; + font-weight: 400; +} + +.label-default { + background-color: #eaecf6; + color: #59595a; + border: 1px solid #e3e6f3; +} + +.label-default[href]:hover, +.label-default[href]:focus { + background-color: #c6cce7; +} + +.label-primary { + background-color: #1582dc; + color: #fff; +} + +.label-primary[href]:hover, +.label-primary[href]:focus { + background-color: #1166ad; +} + +.label-success { + background-color: #15db81; +} + +.label-success[href]:hover, +.label-success[href]:focus { + background-color: #11ac66; +} + +.label-info { + background-color: #15acdc; +} + +.label-info[href]:hover, +.label-info[href]:focus { + background-color: #1188ad; +} + +.label-warning { + background-color: #daac16; +} + +.label-warning[href]:hover, +.label-warning[href]:focus { + background-color: #ac8711; +} + +.label-danger { + background-color: #da3e16; +} + +.label-danger[href]:hover, +.label-danger[href]:focus { + background-color: #ac3111; +} + +/* + * Bootstrap $Carousel + * + */ +.carousel-control { + color: #59595a; + text-shadow: none; +} + +.carousel-control.left, +.carousel-control.right { + background: transparent; + background-image: none; + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); +} + +.carousel-control .icon-prev, +.carousel-control .icon-next { + font-family: FontAwesome; +} + +.carousel-control .icon-prev, +.carousel-control .glyphicon-chevron-left { + left: 50%; +} + +.carousel-control span, +.carousel-control i { + position: absolute; + top: 50%; + z-index: 5; + display: inline-block; + margin-top: -10px; + margin-left: -10px; + width: 20px; + height: 20px; +} + +.carousel-indicators { + bottom: 5px; +} + +.carousel-indicators li { + background-color: #eaecf6; +} + +.carousel-indicators .active { + background-color: #15db81; +} + +#quote-carousel { + width: 100%; + position: relative; + padding: 5px 60px; +} + +#quote-carousel .carousel-control:hover { + color: #59595a; +} + +/* + * $Chat Box + * + */ +.chat-box .panel { + margin-bottom: 5px; +} + +.chat-box .chatbox-user { + margin-bottom: 35px; +} + +.chat-box .chatbox-user .chat-time { + display: block; + text-align: right; +} + +.chat-box .chatbox-user.right .chat-avatar img { + float: right; +} + +.chat-box .chat-avatar { + width: 48px; + display: block; +} + +.chat-box .message { + position: relative; + margin-left: 60px; +} + +.chat-box .message:before { + content: ""; + position: absolute; + left: 0; + border-right: 6px solid #fff; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + top: 10px; + margin-left: -6px; +} + +.chat-box .panel-body { + display: table; + width: 100%; +} + +.chat-box .chatbox-user.right .message { + position: relative; + margin-left: 0; + margin-right: 60px; +} + +.chat-box .chatbox-user.right .message .panel { + background-color: #15db81; + color: #fff; +} + +.chat-box .chatbox-user.right .message .chat-time { + text-align: left; +} + +.chat-box .chatbox-user.right .message:before { + left: 100%; + margin-right: 6px; + margin-left: 0; + border-right: 6px solid transparent; + border-left: 6px solid #15db81; + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; +} + +.chat-box p { + margin: 0; +} + +@-webkit-keyframes opacity { + 0% { + opacity: 1; + filter: alpha(opacity=100); + } + 100% { + opacity: 0.4; + filter: alpha(opacity=40); + } +} + +.chat-box .typing { + display: block; +} + +.chat-box .typing:before, +.chat-box .typing:after { + content: ''; +} + +.chat-box .typing > div, +.chat-box .typing:before, +.chat-box .typing:after { + border-radius: 50%; + width: 8px; + height: 8px; + background-color: rgba(0, 0, 0, 0.5); + display: inline-block; + margin-right: 5px; +} + +.chat-box .typing > div, +.chat-box .typing:before, +.chat-box .typing:after { + -webkit-animation-name: opacity; + -webkit-animation-duration: 1s; + -webkit-animation-iteration-count: infinite; + -moz-animation-name: opacity; + -moz-animation-duration: 1s; + -moz-animation-iteration-count: infinite; +} + +.chat-box .typing > div { + -webkit-animation-delay: 100ms; + -moz-animation-delay: 100ms; +} + +.chat-box .typing:after { + -webkit-animation-delay: 300ms; + -moz-animation-delay: 300ms; +} + +.mail-list { + margin: 0 -1px; +} + +.mail-list .list-group-item { + border-radius: 0; +} + +.mail-list .list-group-item:last-child { + border-bottom: 0; +} + +/* + * $Timeline styles + * + */ +.timeline { + position: relative; + display: table; + width: 100%; + margin-bottom: -15px; +} + +.timeline:before { + position: absolute; + top: 35px; + bottom: 15px; + left: 50%; + width: 4px; + background: #1582dc; + content: ''; + margin-left: -2px; + border-radius: 2px; +} + +.timeline .panel { + position: relative; +} + +.timeline-heading { + display: table; + margin: 0 auto; + margin-bottom: 30px; + padding: 5px 15px; + min-width: 80px; + border-radius: 2px; + background: #1582dc; + color: #fff; + text-align: center; + position: relative; + clear: both; +} + +.timeline-panel { + width: 50%; + position: relative; + clear: both; +} + +.timeline-panel:before { + position: absolute; + top: 10px; + margin: 2px 0 0 -6px; + width: 12px; + height: 12px; + border: 2px solid #f1f4f9; + border-radius: 50%; + background: #1582dc; + content: ""; +} + +.timeline-panel > .panel { + border: 1px solid #c4d1df; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.timeline-panel > .panel:after { + position: absolute; + top: 11px; + right: 100%; + width: 0; + height: 0; + border-width: 6px; + border-style: solid; + border-color: transparent #fff transparent transparent; + content: " "; + pointer-events: none; +} + +.timeline-panel > .panel:before { + position: absolute; + top: 10px; + right: 100%; + width: 0; + height: 0; + border-width: 7px; + border-style: solid; + border-color: transparent #c4d1df transparent transparent; + content: " "; + pointer-events: none; +} + +.timeline-panel:nth-child(even) { + float: right; + padding-left: 20px; + padding-right: 0; +} + +.timeline-panel:nth-child(even):before { + left: 0; +} + +.timeline-panel:nth-child(even) .timeline-date { + left: -190px; + position: absolute; + text-align: right; + margin-top: 6px; + width: 150px; +} + +.timeline-panel:nth-child(odd) { + float: left; + padding-right: 20px; + padding-left: 0; +} + +.timeline-panel:nth-child(odd):before { + right: 0; + margin: 2px -6px 0 0; +} + +.timeline-panel:nth-child(odd) .timeline-content { + float: left; + padding: 0 20px 0 0; +} + +.timeline-panel:nth-child(odd) .timeline-date { + right: -190px; + text-align: left; + position: absolute; + margin-top: 8px; + width: 150px; +} + +.timeline-panel:nth-child(odd) .panel:after { + left: 100%; + border-color: transparent transparent transparent #ffffff; +} + +.timeline-panel:nth-child(odd) .panel:before { + left: 100%; + border-color: transparent transparent transparent #c4d1df; +} + +/* + * $Catalog + * + */ +.switcher { + display: initial; +} + +.switcher .feed { + border-radius: 2px; + overflow: hidden; +} + +.switcher .thumb img { + width: 100%; +} + +.switcher .panel { + position: relative; + display: block; + border: 0; + overflow: hidden; +} + +/* Grid view */ +.view-grid .panel { + min-height: 200px; +} + +/* List view */ +.view-list { + margin: -15px 0 0; +} + +.view-list .feed { + margin: 0; +} + +.view-list .switch-item { + position: relative; + width: 100%; + padding: 0; +} + +.view-list .switcher-content { + padding: 0 15px; +} + +.view-list .panel { + margin-bottom: 1px; + border-radius: 0; + padding: 20px 0; +} + +.view-list .panel-body { + display: inline-block; + vertical-align: top; + padding: 0; +} + +.view-list .thumb { + display: inline-block; + margin-left: 15px; + width: 120px; +} + +/* + * Image $Gallery + * + */ +.superbox > ul { + list-style: none; + padding-left: 0; +} + +.superbox > ul > li { + display: block; + border-radius: 2px; + margin-bottom: 15px; +} + +.superbox .gallery-description { + display: block; + background-color: #fff; + padding: 15px; + border-radius: 0 0 2px 2px; +} + +.superbox .gallery-description .title { + display: block; + text-transform: uppercase; +} + +.gallery-loader { + opacity: 1; + filter: alpha(opacity=100); + background-color: rgba(255, 255, 255, 0.8); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: block; + z-index: 999; + height: 100%; +} + +.portfolio-ajax { + display: none; + position: relative; +} + +.portfolio-ajax .portfolio-container { + padding-top: 50px; + background-color: #fff; +} + +.portfolio-ajax .porfolio-controls { + background-color: #fff; + height: 50px; + z-index: 99999; + padding: 15px; +} + +.portfolio-ajax .porfolio-controls a { + width: 33.3333%; + display: block; + float: left; + vertical-align: middle; +} + +.portfolio-ajax .porfolio-controls a.prev-portfolio-item { + text-align: left; +} + +.portfolio-ajax .porfolio-controls a.next-portfolio-item { + text-align: right; +} + +.portfolio-ajax .porfolio-controls a.close-view { + text-align: center; +} + +.portfolio-ajax .porfolio-controls a.disabled { + color: #999999; +} + +.portfolio-ajax .project-media { + text-align: center; + margin-bottom: 30px; +} + +.portfolio-ajax .portfolio-content { + padding: 15px; +} + +.portfolio-ajax.loading .portfolio-container { + opacity: 0; + filter: alpha(opacity=0); +} + +.portfolio-ajax.loaded .gallery-loader { + opacity: 0; + filter: alpha(opacity=0); + display: none; +} + +@media screen and (min-width: 768px) { + .portfolio-ajax .portfolio-container { + width: 100%; + height: 100%; + position: absolute; + overflow-x: hidden; + overflow-y: auto; + } + + .portfolio-ajax .porfolio-controls { + height: 50px; + width: 100%; + } +} + +/* + * $404_500, Signin, Signup and lockscreen styles + * + */ +html.lockscreen, +html.error-page, +html.error-page, +html.signin, +html.signup, +html.lockscreen body, +html.error-page body, +html.error-page body, +html.signin body, +html.signup body { + height: 100%; +} + +html.lockscreen label, +html.error-page label, +html.error-page label, +html.signin label, +html.signup label { + position: inherit; +} + +.center-wrapper { + display: table; + width: 100%; + height: 100%; + z-index: 1000; + position: relative; +} + +.center-wrapper .center-content { + display: table-cell; + vertical-align: middle; + width: 100%; + height: 100%; + float: none; + z-index: 9999; +} + +.error-number { + font-size: 150px; + line-height: 1; + font-weight: 800; +} + +.error-nav { + padding: 0; +} + +.error-nav li { + display: inline; + padding: 0 10px; +} + +.error-nav li a { + color: #fff; +} + +.lockcode { + max-width: 150px; + display: block; + margin: 0 auto; +} + +.search .search-form { + position: relative; + margin: 25px auto; + max-width: 250px; +} + +.search .search-form .search-button { + width: 34px; + height: 100%; + position: absolute; + right: 0; + overflow: hidden; + background: transparent; + border: none; + outline: none; + color: #59595a; +} + +.search .search-form .form-control { + width: 100%; +} + +.switcher-dash-action { + padding: 0; + list-style: none; + display: inline-block; + width: 100%; +} + +.switcher-dash-action li { + width: 50%; + float: left; + text-align: center; +} + +.switcher-dash-action li:first-child a { + border-radius: 2px 0 0 0; +} + +.switcher-dash-action li:last-child a { + border-radius: 0 2px 0 0; +} + +.switcher-dash-action li.active a { + background: #FFF; +} + +.switcher-dash-action li a { + display: block; + width: 100%; + height: 60px; + line-height: 60px; + background: #eaecf6; + color: #59595a; +} + +.lock-input { + border-color: #fff; +} + +/* + * $Plugins + * + */ +/* + * Select2 + * + */ +.editable-input .select2-choice { + line-height: 29px; + height: auto; +} + +.select2-container .select2-choice { + background-image: none; + border-radius: 2px; + border: 1px solid #e3e6f3; + color: #59595a; +} + +.select2-container.select2-drop-above .select2-choice { + border-bottom-color: #e3e6f3; + border-radius: 0 0 2px 2px; + background-image: none; +} + +.select2-drop { + color: #59595a; + border: 1px solid #e3e6f3; + border-top: 0; + border-radius: 0 0 2px 2px; + box-shadow: none; +} + +.select2-drop.select2-drop-above { + border-top: 1px solid #e3e6f3; + border-bottom: 0; + border-radius: 2px 2px 0 0; + box-shadow: none; +} + +.select2-drop-active { + border: 1px solid #1582dc; +} + +.select2-drop.select2-drop-above.select2-drop-active { + border-top: 1px solid #1582dc; +} + +.select2-drop-auto-width { + border-top: 1px solid #e3e6f3; +} + +.select2-container .select2-choice .select2-arrow { + border-left: 1px solid #e3e6f3; + border-radius: 0 2px 2px 0; + background: transparent; + background-image: none; +} + +html[dir="rtl"] .select2-container .select2-choice .select2-arrow { + border-right: 1px solid #e3e6f3; + border-radius: 2px 0 0 2px; +} + +.select2-search input { + font-family: inherit; + font-size: 13px; + border: 1px solid #e3e6f3; + background: none; + margin-top: 5px; + border-radius: 2px; +} + +.select2-search:after { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 28px; + content: "\e610"; + position: absolute; + right: 15px; + text-align: center; + font-size: 12px; + color: #59595a; + top: 50%; + margin-top: -12px; +} + +.select2-container-active .select2-choice, +.select2-container-active .select2-choices { + border: 1px solid #1582dc; + box-shadow: none; +} + +.select2-dropdown-open .select2-choice { + box-shadow: none; + background-color: #e3e6f3; + background-image: none; +} + +.select2-dropdown-open.select2-drop-above .select2-choice, +.select2-dropdown-open.select2-drop-above .select2-choices { + border: 1px solid #1582dc; + box-shadow: none; +} + +.select2-container-multi .select2-choices { + border: 1px solid #1582dc; + background-image: none; +} + +.select2-container-multi.select2-container-active .select2-choices { + border: 1px solid #1582dc; + box-shadow: none; +} + +.select2-container-multi .select2-choices .select2-search-field input { + font-family: inherit; + color: #59595a; +} + +.select2-default { + color: #59595a !important; +} + +.select2-container-multi .select2-choices .select2-search-choice { + color: #59595a; + border: 1px solid #e3e6f3; + border-radius: 2px; + box-shadow: none; + background-color: #eaecf6; + background-image: none; +} + +.select2-search-choice-close { + background: none; + text-align: center; +} + +.select2-search-choice-close:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 24px; + content: "\e646"; + text-align: center; + font-size: 10px; + color: #59595a; + position: absolute; + left: 0; + top: 50%; + margin-top: -12px; + width: 100%; +} + +.select2-container .select2-choice abbr { + background: none; + width: 24px; + height: 100%; + top: 0; +} + +.select2-container .select2-choice .select2-arrow { + width: 24px; +} + +.select2-container .select2-choice .select2-arrow b { + background: none; + text-align: center; +} + +.select2-container .select2-choice .select2-arrow b:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 24px; + content: "\e64b"; + text-align: center; + font-size: 10px; + color: #59595a; +} + +.select2-results li { + border-radius: 2px; +} + +.select2-results .select2-highlighted { + background: #1582dc; +} + +/* + * twitter typeahead + * + */ +.tt-dropdown-menu { + width: 100%; + box-shadow: none; + border-radius: 2px; + border-top-left-radius: 0; + border-top-right-radius: 0; + border: 1px solid #e3e6f3; + border-top: 0; + margin-top: -1px; +} + +.tt-suggestion.tt-is-under-cursor { + background-color: #1582dc; + background-image: none; +} + +/* + * x-editable + * + */ +.editableform-loading { + background: url('../img/loading.gif') center center no-repeat; +} + +.editable-clear-x { + background: none; +} + +.editable-clear-x:hover { + cursor: pointer; +} + +.editable-clear-x:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 24px; + content: "\e646"; + position: absolute; + text-align: center; + font-size: 12px; + color: #59595a; + top: 50%; + margin-top: -12px; +} + +/* + * Enjoyhint + * + */ +.enjoyhint_btn, +.enjoyhint_next_btn { + border: 2px solid #15db81; + color: #15db81; +} + +.enjoyhint_btn:hover, +.enjoyhint_next_btn:hover { + background-color: #15db81; +} + +/* + * Superbox + * + */ +.superbox { + font-size: 0; + margin-left: -15px; + margin-right: -15px; + margin-top: -10px; +} + +.superbox .title { + font-size: 13px; +} + +.superbox .sub-title { + font-size: 11px; +} + +.superbox-list { + display: inline-block; + *display: inline; + zoom: 1; + border-radius: 2px; + padding-right: 15px; + padding-left: 15px; + margin-bottom: 10px; + margin-top: 10px; + cursor: pointer; +} + +.superbox-list > img { + border-radius: 2px 2px 0 0; +} + +.superbox-img { + max-width: 100%; + width: 100%; + cursor: pointer; +} + +.superbox-show { + text-align: center; + position: relative; + background: #4a4b5b; + width: 100%; + float: left; + padding: 25px; + display: none; + margin-top: -5px; +} + +.superbox-current-img { + max-width: 100%; +} + +.superbox-img:hover { + opacity: 0.8; + filter: alpha(opacity=80); +} + +.superbox-float { + float: left; +} + +.superbox-close { + opacity: 7; + filter: alpha(opacity=700); + cursor: pointer; + position: absolute; + top: 25px; + right: 25px; + background: url(../img/close.gif) no-repeat center center; + width: 35px; + height: 35px; +} + +.superbox-close:hover { + opacity: 1; + filter: alpha(opacity=100); +} + +/* + * Bootstrap tags input + * + */ +.bootstrap-tagsinput .tag { + margin-bottom: 5px; + display: inline-block; +} + +/* + * Chosen Input Select + * + */ +.chosen-container-single .chosen-single, +.chosen-container-multi .chosen-choices, +.bootstrap-tagsinput { + border: 1px solid #e3e6f3; + border-radius: 2px; + box-shadow: none; + -webkit-transition: border .25s linear, color .25s linear, background-color .25s linear; + transition: border .25s linear, color .25s linear, background-color .25s linear; + -webkit-appearance: none; + font-weight: 400; + font-size: 13px; + min-height: 34px; + padding: 6px 12px; + line-height: 1.42857143; + color: #59595a; + background-color: #fff; + background-image: none; +} + +.chosen-container-active.chosen-with-drop .chosen-single { + border: 1px solid #e3e6f3; + background-image: none; +} + +.chosen-container .chosen-drop, +.chosen-container-single .chosen-search input[type=text] { + border: 1px solid #e3e6f3; +} + +.chosen-container .chosen-drop { + border-top: 0; + box-shadow: 0px 4px 5px rgba(88, 96, 114, 0.15); + border-radius: 0 0 2px 2px; +} + +.chosen-container-multi.chosen-with-drop .chosen-choices { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + border-bottom: 0; +} + +.chosen-container-single .chosen-search input[type=text] { + background: none; +} + +.chosen-container-single .chosen-search:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 24px; + content: "\e610"; + position: absolute; + right: 5px; + width: 24px; + height: 24px; + text-align: center; + font-size: 12px; + color: #59595a; + top: 50%; + margin-top: -12px; +} + +.chosen-container-single .chosen-single div b { + background: none; +} + +.chosen-container-single .chosen-single div b:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 24px; + content: "\e64b"; + position: absolute; + right: 5px; + width: 24px; + height: 24px; + text-align: center; + font-size: 12px; + color: #59595a; + top: 50%; + margin-top: -12px; +} + +.chosen-container-active.chosen-with-drop .chosen-single div b:before { + content: "\e648"; +} + +.chosen-container-single .chosen-single abbr { + background: none; + position: absolute; + right: 30px; + width: 24px; + height: 24px; + top: 50%; + margin-top: -12px; + text-align: center; + line-height: 24px; +} + +.chosen-container-single .chosen-single abbr:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + content: "\e646"; + font-size: 12px; + color: #e3e6f3; +} + +.chosen-container .chosen-results li.highlighted, +.chosen-container .chosen-results li.result-selected { + background-color: #1582dc; + background-image: none; + color: #fff; +} + +.chosen-container-multi .chosen-choices li.search-choice { + margin: 3px 5px 3px 0; +} + +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close { + background: none; + width: 16px; + height: 16px; + top: 2px; +} + +.chosen-container-multi .chosen-choices li.search-choice .search-choice-close:before { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 16px; + content: "\e646"; + position: absolute; + right: 0; + width: 16px; + height: 16px; + text-align: center; + font-size: 12px; + color: #59595a; + top: 50%; + margin-top: -8px; +} + +.chosen-container-multi .chosen-choices li.search-choice { + background-image: none; + background-color: #eaecf6; + border-color: #e3e6f3; + box-shadow: none; +} + +.chosen-container-multi .chosen-choices li.search-field input[type=text] { + -webkit-font-smoothing: antialiased; +} + +.center-block .chosen-container { + display: block; + margin: 0 auto; +} + +/* + * Parsley Validation States + * + */ +.parsley-errors-list { + list-style: none; + padding: 0; + margin-bottom: 0; +} + +.parsley-success { + border-color: #15db81; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.parsley-success:focus { + border-color: #11ac66; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #66f0b1; +} + +.parsley-warning { + border-color: #daac16; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.parsley-warning:focus { + border-color: #ac8711; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f0cf66; +} + +.parsley-error { + border-color: #da3e16; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); +} + +.parsley-error:focus { + border-color: #ac3111; + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 6px #f08266; +} + +.parsley-error-list { + color: #a94442; +} + +/* +* Data tables +* +*/ +.sorting:after, +.sorting_asc:after, +.sorting_desc:after, +.sorting_asc_disabled:after, +.sorting_desc_disabled:after { + font-family: FontAwesome; + float: right; + color: #ddd; +} + +.sorting:after { + content: "\f0dc"; +} + +.sorting_asc:after, +.sorting_asc_disabled:after { + content: "\f0de"; + color: #59595a; +} + +.sorting_desc:after, +.sorting_desc_disabled:after { + content: "\f0dd"; + color: #59595a; +} + +table.dataTable.no-footer { + border-bottom-color: #e3e6f3; +} + +table.dataTable, +.editable-datatable, +table.dataTable .form-control { + width: 100% !important; +} + +.datatable-top, +table.dataTable { + margin-bottom: 15px; +} + +.datatable-top, +.datatable-bottom { + display: table; + width: 100%; +} + +.datatable-bottom .pagination { + margin: 0; +} + +/* +* Stepy Wizard +* +*/ + +.stepy { + width: 100%; + display: block; + background-color: #fff +} + +.stepy-header { + background-color: #1582dc; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-bottom: 1px solid #1166ad +} + +.stepy-header li { + background-color: transparent; + position: relative; + line-height: 1 +} + +.stepy-header li:before { + position: absolute; + top: 1px; + right: -14px; + z-index: 9; + display: block; + border: 23px solid transparent; + border-right: 0; + border-left: 22px solid #1582dc; + content: "" +} + +.stepy-header li:after { + position: absolute; + top: 0; + right: -15px; + z-index: 1; + display: block; + border: 24px solid transparent; + border-right: 0; + border-left: 23px solid #1166ad; + content: "" +} + +.stepy-header li div { + font-weight: 400; + font-family: inherit; + color: #fff; + text-shadow: none; + text-transform: uppercase; + font-size: 14px +} + +.stepy-header li span, .stepy-header li.stepy-active div, .stepy-header li.stepy-active span { + color: #fff +} + +.stepy-header li.stepy-active div { + font-weight: 800 +} + +.stepy-step { + background: transparent; + width: 100% +} + +.stepy-step:before, .stepy-step:after { + content: " "; + display: table +} + +.stepy-step:after { + clear: both +} + +.stepy-step legend { + border-radius: 2px; + background-color: #2e353d; + color: #fff; + padding: 0 15px; + font-size: 13px +} + +/* +* Jstree +* +*/ +.jstree-default .jstree-clicked, +.jstree-default .jstree-hovered { + background: #e0effc; + box-shadow: none; +} + +.jstree-default .jstree-wholerow-clicked { + background: #e0effc; + border-radius: 2px; +} + +.jstree-default.jstree-checkbox-no-clicked .jstree-clicked.jstree-hovered, +.jstree-default.jstree-checkbox-no-clicked > .jstree-wholerow-ul .jstree-wholerow-clicked.jstree-wholerow-hovered, +.jstree-default .jstree-wholerow-hovered, +.jstree-default-responsive .jstree-wholerow-hovered { + background: #e0effc; +} + +.jstree-default .jstree-node, +.jstree-default .jstree-anchor, +.jstree-default .jstree-wholerow { + border-radius: 2px; +} + +.jstree-default .jstree-search { + color: #da3e16; +} + +/* +* IonSLider +* +*/ +.irs-line-mid, +.irs-line-left, +.irs-line-right, +.irs-diapason, +.irs-slider { + background: url(../img/sprite-skin-flat.png) repeat-x; +} + +.irs-slider { + background-position: 0 -90px; +} + +.irs-from, +.irs-to, +.irs-single { + background: #1582dc; +} + +.irs-from:after, +.irs-to:after, +.irs-single:after { + border-top-color: #1582dc; +} + +.irs-min, +.irs-max { + color: #59595a; + background: #eaecf6; +} + +.irs-line { + border-radius: 2px; +} + +/* +* Owl Carousel Owl Demo Theme +* v1.3.3 +*/ +.owl-theme .owl-controls .owl-page span { + background: rgba(0, 0, 0, 0.5); + width: 8px; + height: 8px; + margin: 5px; +} + +/* + * + * JVectorMap + * + */ +.jvectormap-label { + position: absolute; + border-radius: 2px; + color: white; + font-family: inherit; + font-size: smaller; + padding: 3px; + font-size: inherit; +} + +.jvectormap-zoomin, +.jvectormap-zoomout { + position: absolute; + left: 15px; + color: white; + cursor: pointer; + font-size: 13px; + text-align: center; + padding: 5px 7px; + border-radius: 2px; + width: auto; + height: auto; + line-height: 1; +} + +.jvectormap-zoomin { + top: 15px; +} + +.jvectormap-zoomout { + top: 50px; +} + +/* + * + * Image Crop + * + */ +.jcrop-holder #preview-pane { + display: block; + position: absolute; + z-index: 999; + top: 0; + right: -150px; + padding: 5px; + border: 1px solid #e3e6f3; + background-color: #fff; + border-radius: 2px; + box-shadow: 0px 0px 5px rgba(88, 96, 114, 0.15); +} + +/* The Javascript code will set the aspect ratio of the crop + area based on the size of the thumbnail preview, + specified here */ +#preview-pane .preview-container { + width: 250px; + height: 170px; + overflow: hidden; +} + +/* + * + * Slimscroll + * + */ +.slimScrollBar { + background-color: rgba(0, 0, 0, 0.3) !important; +} + +/* + * + * Daterange Picker + * + */ +.daterangepicker { + border-radius: 2px; + font-size: 13px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + margin-top: -1px; +} + +.daterangepicker .ranges .input-mini { + background-color: transparent; + border: 1px solid #e3e6f3; + border-radius: 2px; + color: #59595a; +} + +.daterangepicker .calendar-date { + border-radius: 2px; + border: 1px solid #e3e6f3; +} + +.daterangepicker td.available + td.start-date { + border-radius: 2px 0 0 2px; +} + +.daterangepicker td.in-range + td.end-date { + border-radius: 0 2px 2px 0; +} + +.daterangepicker td.available:hover, +.daterangepicker th.available:hover { + background: #eaecf6; +} + +.daterangepicker td.active, +.daterangepicker td.active:hover { + background-color: #1582dc; + border-color: #1582dc; + color: #fff; +} + +.daterangepicker td, +.daterangepicker th { + border-radius: 2px; +} + +.daterangepicker .calendar th, +.daterangepicker .calendar td { + font-family: inherit; +} + +.daterangepicker td.start-date.end-date { + border-radius: 2px !important; +} + +/* + * + * Date Picker + * + */ +.datepicker-dropdown { + border-radius: 2px; + font-size: 13px; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); + padding: 15px; +} + +.datepicker td.active:hover, +.datepicker td.active:hover:hover, +.datepicker td.active:focus, +.datepicker td.active:hover:focus, +.datepicker td.active:active, +.datepicker td.active:hover:active, +.datepicker td.active.active, +.datepicker td.active:hover.active, +.datepicker td.active.disabled, +.datepicker td.active:hover.disabled, +.datepicker td.active[disabled], +.datepicker td.active:hover[disabled] { + background-image: none; + background-color: #1582dc; + border-color: #1582dc; + color: #fff; + text-shadow: none; +} + +.datepicker td, +.datepicker th { + border-radius: 2px; + min-width: 30px; + min-height: 30px; +} + +.datepicker-orient-bottom.datepicker:before { + top: initial; + bottom: -7px; + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 0; + border-top: 7px solid #ccc; + border-top-color: rgba(0, 0, 0, 0.2); +} + +.datepicker-orient-bottom.datepicker:after { + top: initial; + bottom: -6px; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 0; + border-top: 6px solid #ffffff; +} + +/* + * + * Medium Editor + * + */ +@-webkit-keyframes pop-upwards { + 0% { + -webkit-transform: translate3d(0.97, 0, 0, 1, 0, 12); + transform: translate3d(0.97, 0, 0, 1, 0, 12); + opacity: 0; + filter: alpha(opacity=0); + } + 20% { + -webkit-transform: translate3d(0.99, 0, 0, 1, 0, 2); + transform: translate3d(0.99, 0, 0, 1, 0, 2); + opacity: 0.7; + filter: alpha(opacity=70); + } + 40% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, -1); + transform: translate3d(1, 0, 0, 1, 0, -1); + opacity: 1; + filter: alpha(opacity=100); + } + 70% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, 0); + transform: translate3d(1, 0, 0, 1, 0, 0); + opacity: 1; + filter: alpha(opacity=100); + } + 100% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, 0); + transform: translate3d(1, 0, 0, 1, 0, 0); + opacity: 1; + filter: alpha(opacity=100); + } +} + +@keyframes pop-upwards { + 0% { + -webkit-transform: translate3d(0.97, 0, 0, 1, 0, 12); + transform: translate3d(0.97, 0, 0, 1, 0, 12); + opacity: 0; + filter: alpha(opacity=0); + } + 20% { + -webkit-transform: translate3d(0.99, 0, 0, 1, 0, 2); + transform: translate3d(0.99, 0, 0, 1, 0, 2); + opacity: 0.7; + filter: alpha(opacity=70); + } + 40% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, -1); + transform: translate3d(1, 0, 0, 1, 0, -1); + opacity: 1; + filter: alpha(opacity=100); + } + 70% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, 0); + transform: translate3d(1, 0, 0, 1, 0, 0); + opacity: 1; + filter: alpha(opacity=100); + } + 100% { + -webkit-transform: translate3d(1, 0, 0, 1, 0, 0); + transform: translate3d(1, 0, 0, 1, 0, 0); + opacity: 1; + filter: alpha(opacity=100); + } +} + +.medium-toolbar-arrow-under:after { + top: 50px; + border-color: #4f5061 transparent transparent transparent; +} + +.medium-toolbar-arrow-over:before { + top: -8px; + border-color: transparent transparent #4f5061 transparent; +} + +.medium-editor-toolbar { + background-color: #4f5061; + border-radius: 2px; + -webkit-transition: top 0.075s ease-out, left 0.075s ease-out; + transition: top 0.075s ease-out, left 0.075s ease-out; +} + +.medium-editor-toolbar li button { + min-width: 50px; + height: 50px; + border: 0; + border-right: 1px solid #565769; + background-color: #4f5061; + color: #fff; + -webkit-transition: background-color 0.2s ease-in; + transition: background-color 0.2s ease-in; +} + +.medium-editor-toolbar li button:hover { + background-color: #484959; + color: #daac16; +} + +.medium-editor-toolbar li .medium-editor-button-first { + border-top-left-radius: 2px; + border-bottom-left-radius: 2px; +} + +.medium-editor-toolbar li .medium-editor-button-last { + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; +} + +.medium-editor-toolbar li .medium-editor-button-active { + background-color: #58596c; +} + +.medium-editor-toolbar-form-anchor { + background: #4f5061; + color: #59595a; + border-radius: 2px; +} + +.medium-editor-toolbar-form-anchor input { + height: 50px; + background: #4f5061; + color: #ccc; + border-radius: 2px 0 0 2px; +} + +.medium-editor-toolbar-form-anchor a { + color: #fff; +} + +.medium-editor-toolbar-anchor-preview { + background: #4f5061; + color: #fff; + border-radius: 2px; +} + +.medium-editor-placeholder:after { + color: #b3b3b1; +} + +/* + * + * Bootstrap Slider + * http://www.eyecon.ro/bootstrap-slider/ + * + */ +.slider.slider-horizontal { + width: 100% !important; +} + +.slider.slider-horizontal .slider-track { + height: 5px; +} + +.slider.slider-horizontal .slider-selection { + background-image: none; +} + +.slider-track { + background-color: #d0dbec; + background-image: none; + border-radius: 2px; + box-shadow: none; +} + +.slider-selection { + position: absolute; + background-color: #7f8bc8; + border-radius: 2px; + box-shadow: none; +} + +.slider-handle { + background: #fff; + opacity: 1; + filter: alpha(opacity=100); + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #7f8bc8 0px 0px 0px 1px; +} + +.slider.slider-horizontal .slider-handle { + margin-top: -8px; +} + +/* Slider Color Variants */ +.slider-info .slider-selection { + background-color: #15acdc; +} + +.slider-info .slider-handle { + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #15acdc 0px 0px 0px 1px; +} + +.slider-primary .slider-selection { + background-color: #1582dc; +} + +.slider-primary .slider-handle { + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #1582dc 0px 0px 0px 1px; +} + +.slider-success .slider-selection { + background-color: #15db81; +} + +.slider-success .slider-handle { + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #15db81 0px 0px 0px 1px; +} + +.slider-warning .slider-selection { + background-color: #daac16; +} + +.slider-warning .slider-handle { + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #daac16 0px 0px 0px 1px; +} + +.slider-danger .slider-selection { + background-color: #da3e16; +} + +.slider-danger .slider-handle { + box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 5px, #da3e16 0px 0px 0px 1px; +} + +.slider-striped .slider .slider-selection { + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent); + background-size: 40px 40px; +} + +/* + * + * toastr + * https://github.com/CodeSeven/toastr + * + */ +#toast-container > div { + border-radius: 2px; + box-shadow: none; +} + +.toast { + background-color: #030303; +} + +.toast-success { + background-color: #15db81; +} + +.toast-error { + background-color: #da3e16; +} + +.toast-info { + background-color: #15acdc; +} + +.toast-warning { + background-color: #daac16; +} + +#toast-container > :hover { + box-shadow: none; +} + +/* + * + * Fullcalendar + * http://arshaw.com/fullcalendar + * + */ +.fc-icon { + font-size: inherit; +} + +.external-events { + border-bottom: 1px solid #e3e6f3; + padding: 0 0 20px 0; +} + +.fc-event, +.external-event { + border: transparent; + /* default BORDER color */ + cursor: default; + text-align: center; + font-weight: 400; + font-size: 13px; +} + +.external-events .external-event { + cursor: move; + display: inline-block; + margin: 0 5px 10px 0; +} + +.external-event:hover { + cursor: move; +} + +a.fc-event, +.fc-event-draggable { + cursor: pointer; +} + +.fc-toolbar { + display: none; + visibility: hidden; +} + +.fc-content { + margin: 0 -1px; +} + +.fc-event { + cursor: default; + line-height: inherit; + padding: .2em .6em .3em; +} + +.fc-event.bg-primary { + color: #ffffff; +} + +.fc-event.bg-default { + color: #59595a; +} + +.fc-event.bg-warning { + color: #ffffff; +} + +.fc-event.bg-success { + color: #ffffff; +} + +.fc-event.bg-info { + color: #ffffff; +} + +.fc-event.bg-danger { + color: #ffffff; +} + +/* + * + * Switchery + * http://abpetkov.github.io/switchery/ + * + */ +.switchery { + background-color: #f5f6fb !important; + border: 1px solid #e3e6f3; + border-radius: 20px; + cursor: pointer; + display: inline-block; + height: 30px; + position: relative; + vertical-align: middle; + width: 50px; +} + +.switchery > small { + background: #fff; + border-radius: 100%; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); + height: 28px; + position: absolute; + top: 0; + width: 28px; +} + +/* + * FuelUX Pill + * + */ +.pillbox { + margin-bottom: 10px; + padding: 5px; + border: 1px solid #e3e6f3; + border-radius: 2px; + line-height: 1; +} + +.pillbox ul { + margin: 0; + padding: 0; +} + +.pillbox li { + display: inline-block; + margin: 2px; + padding: 2px 4px; + vertical-align: middle; + cursor: pointer; + border-radius: 2px; + white-space: nowrap; + font-size: 12px; +} + +.pillbox li:after { + font-family: 'themify'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + position: relative; + content: " \e646"; + font-size: 10px; + margin-left: 10px; +} + +.pillbox li.status-important { + background-color: #da3e16; +} + +.pillbox li.status-warning { + background-color: #daac16; +} + +.pillbox li.status-success { + background-color: #15db81; +} + +.pillbox li.status-info { + background-color: #15acdc; +} + +/* + * FuelUX Spinner + * + */ +.spinner .btn.disabled { + cursor: not-allowed; +} + +/* + * FuelUX Wizard + * + */ +.wizard { + position: relative; + overflow: hidden; + border-bottom: 1px solid #eaecf6; + background-color: #eaecf6; + border-radius: 2px 2px 0; +} + +.wizard ul { + margin: 0; + padding: 0; + list-style: none; +} + +.wizard ul li { + position: relative; + margin: 0; + padding-left: 30px; + padding-right: 15px; + height: 40px; + line-height: 40px; + background: transparent; + cursor: default; + float: left; + white-space: nowrap; +} + +.wizard ul li:before { + position: absolute; + top: 0; + right: -14px; + z-index: 9; + display: block; + border: 21px solid transparent; + border-right: 0; + border-left: 14px solid #eaecf6; + content: ""; +} + +.wizard ul li:after { + position: absolute; + top: -1px; + right: -15px; + z-index: 1; + display: block; + border: 22px solid transparent; + border-right: 0; + border-left: 15px solid #cdd2ea; + content: ""; +} + +.wizard ul li .badge { + margin-right: 8px; +} + +.wizard ul li.complete { + background: #eaecf6; +} + +.wizard ul li.complete .badge { + background: #15db81; +} + +.wizard ul li.complete:before { + border-left: 14px solid #eaecf6; +} + +.wizard ul li.complete:hover { + background: #e7eff8; + cursor: pointer; +} + +.wizard ul li.complete:hover:before { + border-left: 14px solid #e7eff8; +} + +.wizard ul li.active { + background: #fff; + color: #1582dc; +} + +.wizard ul li.active:before { + border-left: 14px solid #fff; + right: -14px; +} + +.wizard ul li.active:after { + right: -15px; +} + +.wizard ul li:first-child { + padding-left: 20px; + border-radius: 2px 0 0; +} + +.wizard ul.previous-disabled li.complete { + cursor: default; +} + +.wizard ul.previous-disabled li.complete:hover { + background: #f3f4f5; +} + +.wizard ul.previous-disabled li.complete:hover:before { + border-left-color: #f3f4f5; +} + +.wizard .actions { + position: absolute; + right: 0; + float: right; + padding-top: 6px; + padding-right: 15px; + padding-left: 15px; + vertical-align: middle; + line-height: 37px; +} + +.wizard .actions a { + margin-right: 8px; + font-size: 12px; + line-height: 45px; +} + +.step-content { + padding: 15px; +} + +.step-content .step-pane { + display: none; +} + +.step-content .active { + display: block; +} + +.step-content .active .btn-group .active { + display: inline-block; +} + +/* + * iCheck + * + */ +.icheckbox, +.iradio { + display: inline-block; + *display: inline; + vertical-align: middle; + margin: 0; + padding: 0; + width: 18px; + height: 18px; + background: url(../img/minimal.png) no-repeat; + border: none; + cursor: pointer; +} + +.icheckbox { + background-position: 0 0; +} + +.icheckbox.hover { + background-position: -20px 0; +} + +.icheckbox.checked { + background-position: -40px 0; +} + +.icheckbox.disabled { + background-position: -60px 0; + cursor: default; +} + +.icheckbox.checked.disabled { + background-position: -80px 0; +} + +.iradio { + background-position: -100px 0; +} + +.iradio.hover { + background-position: -120px 0; +} + +.iradio.checked { + background-position: -140px 0; +} + +.iradio.disabled { + background-position: -160px 0; + cursor: default; +} + +.iradio.checked.disabled { + background-position: -180px 0; +} + +/* HiDPI support */ +@media (-o-min-device-pixel-ratio: 5/4), (-webkit-min-device-pixel-ratio: 1.25), (min-resolution: 120dpi) { + .icheckbox, + .iradio { + background-image: url(../img/minimal@2x.png); + background-size: 200px 20px; + } +} + +/* + * Various $Charts plugin styles + * + */ +/* Morris Tooltip */ +.morris-hover { + position: absolute; + z-index: 1000; +} + +.morris-hover.morris-default-style { + border-radius: 2px; + padding: 6px; + color: #ffffff; + font-size: 12px; + text-align: center; +} + +.morris-hover.morris-default-style .morris-hover-row-label { + font-weight: bold; + margin: 0.25em 0; +} + +.morris-hover.morris-default-style .morris-hover-point { + white-space: nowrap; + margin: 0.1em 0; +} + +/* Sparkline Tooltip */ +#jqstooltip { + display: table; + border-radius: 2px; + padding: 15px; +} + +/* Flot Charts */ +#tooltip { + position: absolute; + display: none; + padding: 5px 10px; + border: 0; + line-height: 1; +} + +#tooltip:before { + content: ''; + display: block; + position: absolute; + top: 4px; + right: 100%; + width: 0; + height: 0; + border-style: solid; + border-width: 6px; +} + +/* Pie Charts */ +.piechart { + position: relative; + display: inline-block; +} + +.piechart canvas { + position: absolute; + top: 0; + left: 0; +} + +.piechart > span { + display: table; + width: 100%; + height: 100%; +} + +.piechart > span > span { + display: table-cell; + vertical-align: middle; +} + +.piechart .percent { + display: block; + font-size: 18px; + position: relative; +} + +.piechart .percent:after { + content: '%'; + font-size: .5em; + position: absolute; + top: 0; +} + +/* Chart dimensions */ +.chart { + border: 0; + width: 100%; + height: 200px; +} + +.chart-legend.first { + padding-top: 80px; +} + +/* + * Maps + * + */ +.map img, +#map img { + max-width: none !important; +} + +#map, +.map { + width: 100%; + height: 100%; + background: transparent; + min-height: 300px; + position: relative; +} + +#map { + min-height: 250px; +} + +#map .jvectormap-container { + min-height: 300px; +} + +/* Google Maps */ +.gm-style-cc { + display: none !important; +} + +#map_canvas { + width: 100%; + height: 400px; +} + +/* + * $Sortable elements (Jquery Sortable) + * + */ +.sortable .list-group-item, +.handles .list-group-item { + padding: 15px; +} + +.connected, +.sortable, +.exclude, +.handles { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.connected li, +.sortable li, +.exclude li, +.handles li { + border: 1px solid transparent; +} + +.connected li:not(:last-child), +.sortable li:not(:last-child), +.exclude li:not(:last-child), +.handles li:not(:last-child) { + margin-bottom: 1px; + border: 1px solid transparent; + border-radius: 2px; +} + +.sortable > li, +.handles span { + cursor: move; +} + +.handles span { + float: left; +} + +#connected { + overflow: hidden; + margin: auto; +} + +.connected { + float: left; +} + +.connected.no2 { + float: right; +} + +.sortable-placeholder { + list-style: none; + border: 1px dashed #ddd !important; + min-height: 50px; + width: 100%; +} + +/* + * Nestable elements (Jquery Nestable) + * + */ +.dd { + position: relative; + display: block; + margin: 0; + padding: 0; + list-style: none; +} + +.dd-list { + display: block; + position: relative; + margin: 0; + padding: 0; + list-style: none; +} + +.dd-list .dd-list { + padding-left: 30px; +} + +.dd-collapsed .dd-list { + display: none; +} + +.dd-item, +.dd-empty, +.dd-placeholder { + display: block; + position: relative; + margin: 0; + padding: 0; + min-height: 20px; + line-height: 20px; +} + +.dd-handle { + display: block; + margin: 5px 0; + padding: 10px; + text-decoration: none; + border: 1px solid #e3e6f3; + background: #fff; + border-radius: 2px; +} + +.dd-handle:hover { + color: #2ea8e5; + background: #fff; +} + +.dd-item > button { + display: block; + position: relative; + cursor: pointer; + float: left; + width: 25px; + height: 30px; + padding: 0; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + border: 0; + background: transparent; + line-height: 40px; + text-align: center; + font-weight: bold; +} + +.dd-item > button:before { + content: "+"; + display: block; + position: absolute; + width: 100%; + text-align: center; + text-indent: 0; +} + +.dd-item > button[data-action="collapse"]:before { + content: "-"; +} + +.dd-placeholder, +.dd-empty { + margin: 5px 0; + padding: 0; + min-height: 30px; + background: transparent; + border: 1px dashed #ddd; +} + +.dd-empty { + border: 1px dashed #bbb; + min-height: 100px; + background-color: #e5e5e5; + background-image: -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), -webkit-linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff); + background-image: linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff), linear-gradient(45deg, #ffffff 25%, transparent 25%, transparent 75%, #ffffff 75%, #ffffff); + background-size: 60px 60px; + background-position: 0 0, 30px 30px; +} + +.dd-dragel { + position: absolute; + pointer-events: none; + z-index: 9999; +} + +.dd-dragel > .dd-item .dd-handle { + margin-top: 0; +} + +.dd-dragel .dd-handle { + box-shadow: 2px 4px 6px 0 rgba(0, 0, 0, 0.1); +} + +/** + * Nestable Extras + */ +#nestable-output, +#nestable2-output { + width: 100%; + background: #fff; + font-size: 10px; +} + +#nestable2 .dd-item > button:before { + color: #fff; +} + +@media only screen and (min-width: 700px) { + .dd + .dd { + margin-left: 2%; + } +} + +.dd-hover > .dd-handle { + background: #2ea8e5 !important; +} + +/** + * Nestable Draggable Handles + */ +.dd3-content { + display: block; + margin: 5px 0; + padding: 10px 10px 10px 50px; + text-decoration: none; + border: 1px solid #e3e6f3; + background: #ffffff; + border-radius: 2px; +} + +.dd3-content:hover { + background: #fff; +} + +.dd-dragel > .dd3-item > .dd3-content { + margin: 0; +} + +.dd3-item > button { + margin-left: 40px; +} + +.dd3-handle { + position: absolute; + margin: 0; + left: 0; + top: 0; + cursor: pointer; + width: 38px; + text-indent: 100%; + white-space: nowrap; + overflow: hidden; + border: 1px solid #e3e6f3; + background: #ffffff; + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.dd3-handle:before { + content: '≡'; + display: block; + position: absolute; + left: 0; + top: 7px; + width: 100%; + text-align: center; + text-indent: 0; + font-size: 26px; + font-weight: normal; +} + +.dd3-handle:hover { + background: #ddd; +} + +/* + * $Utilities Classes + * + */ +/* p,m,b = padding,margin,border + * Directions + * t,b,r,l,n = top,bottom,right,left, negative + * Sizing + * xs,sm,md,df,lg = extra small(@xs),small(@sm),medium(@md),default(@df),large(@lg) + */ +.ptl { + position: absolute; + top: 0; + left: 0; +} + +.ptr { + position: absolute; + top: 0; + right: 0; +} + +.pbl { + position: absolute; + bottom: 0; + left: 0; +} + +.pbr { + position: absolute; + bottom: 0; + right: 0; +} + +/* Set background color to transparent */ +.bg-none { + background-color: transparent; + box-shadow: none; +} + +.shadow { + box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); +} + +.no-shadow { + box-shadow: none; +} + +/* Margins */ +.no-m { + margin: 0 !important; +} + +.mn { + margin-right: -15px; + margin-left: -15px; +} + +.mrn { + margin-right: -15px; +} + +.mln { + margin-left: -15px; +} + +.mbn { + margin-bottom: -15px; +} + +.ml0 { + margin-left: 0; +} + +.mr0 { + margin-right: 0; +} + +.mt0 { + margin-top: 0; +} + +.mb0 { + margin-bottom: 0; +} + +.m25 { + margin: 25px; +} + +.mr25 { + margin-right: 25px; +} + +.ml25 { + margin-left: 25px; +} + +.mt25 { + margin-top: 25px; +} + +.mb25 { + margin-bottom: 25px; +} + +.m20 { + margin: 20px; +} + +.mr20 { + margin-right: 20px; +} + +.ml20 { + margin-left: 20px; +} + +.mt20 { + margin-top: 20px; +} + +.mb20 { + margin-bottom: 20px; +} + +.m15 { + margin: 15px; +} + +.mr15 { + margin-right: 15px; +} + +.ml15 { + margin-left: 15px; +} + +.mt15 { + margin-top: 15px; +} + +.mb15 { + margin-bottom: 15px; +} + +.m10 { + margin: 10px; +} + +.mr10 { + margin-right: 10px; +} + +.ml10 { + margin-left: 10px; +} + +.mt10 { + margin-top: 10px; +} + +.mb10 { + margin-bottom: 10px; +} + +.m5 { + margin: 5px; +} + +.mr5 { + margin-right: 5px; +} + +.ml5 { + margin-left: 5px; +} + +.mt5 { + margin-top: 5px; +} + +.mb5 { + margin-bottom: 5px; +} + +/* Padding space */ +.no-p { + padding: 0 !important; +} + +.pl0 { + padding-left: 0; +} + +.pr0 { + padding-right: 0; +} + +.pt0 { + padding-top: 0; +} + +.pb0 { + padding-bottom: 0; +} + +.p50 { + padding: 50px; +} + +.pr50 { + padding-right: 50px; +} + +.pl50 { + padding-left: 50px; +} + +.pt50 { + padding-top: 50px; +} + +.pb50 { + padding-bottom: 50px; +} + +.p25 { + padding: 25px; +} + +.pr25 { + padding-right: 25px; +} + +.pl25 { + padding-left: 25px; +} + +.pt25 { + padding-top: 25px; +} + +.pb25 { + padding-bottom: 25px; +} + +.p20 { + padding: 20px; +} + +.pr20 { + padding-right: 20px; +} + +.pl20 { + padding-left: 20px; +} + +.pt20 { + padding-top: 20px; +} + +.pb20 { + padding-bottom: 20px; +} + +.p15 { + padding: 15px; +} + +.pr15 { + padding-right: 15px; +} + +.pl15 { + padding-left: 15px; +} + +.pt15 { + padding-top: 15px; +} + +.pb15 { + padding-bottom: 15px; +} + +.p10 { + padding: 10px; +} + +.pr10 { + padding-right: 10px; +} + +.pl10 { + padding-left: 10px; +} + +.pt10 { + padding-top: 10px; +} + +.pb10 { + padding-bottom: 10px; +} + +.p5 { + padding: 5px; +} + +.pr5 { + padding-right: 5px; +} + +.pl5 { + padding-left: 5px; +} + +.pt5 { + padding-top: 5px; +} + +.pb5 { + padding-bottom: 5px; +} + +/* Borders */ +.no-b { + border: 0; +} + +td.no-b { + border-top: 0 !important; +} + +.bordered { + border: 1px solid #e3e6f3; +} + +.bb { + border-bottom: 1px solid #e3e6f3; +} + +.bt { + border-top: 1px solid #e3e6f3; +} + +.bl { + border-left: 1px solid #e3e6f3; +} + +.br { + border-right: 1px solid #e3e6f3; +} + +.avatar.bordered { + border: 3px solid rgba(255, 255, 255, 0.5); +} + +/* Radius */ +.no-radius { + border-radius: 0; +} + +.rounded { + border-radius: 2px; +} + +.brtl { + border-top-left-radius: 2px; +} + +.brtr { + border-top-right-radius: 2px; +} + +.brbl { + border-bottom-left-radius: 2px; +} + +.brbr { + border-bottom-right-radius: 2px; +} + +.overflow-hidden { + overflow: hidden; +} + + +.fontawesome-list a { + display: block; + margin-left: 30px; + height: 32px; + color: #59595a; + font-size: 1em; + line-height: 32px; +} + +.fontawesome-list .fa { + position: absolute; + top: 9px; + left: 20px; + -webkit-transition: all 150ms linear; + transition: all 150ms linear; +} + +.themify-icons .fa-hover { + display: block; + padding-left: 45px; + height: 32px; + color: #59595a; + font-size: 1em; + line-height: 32px; +} + +.themify-icons span { + position: absolute; + top: 9px; + left: 20px; + -webkit-transition: all 150ms linear; + transition: all 150ms linear; +} + +.fontawesome-list a:hover .fa, +.themify-icons .fa-hover:hover span { + top: 5px; + color: #15db81; + font-size: 1.5em; +} + +.form-horizontal.bordered-group .form-group { + border-bottom: 1px solid #E7EBF3; + padding-bottom: 15px; +} + +.form-horizontal.bordered-group .form-group:last-child { + border-bottom: 1px solid transparent; + padding: 0; +} + +.switcha > div { + float: left; +} + +.services .service { + margin: 0 30px 25px; + text-align: center; +} + +.service-icon { + margin: 0 auto 15px; + width: 60px; + line-height: 60px; + font-size: 30px; + color: #D6D6D6; + border-radius: 50%; +} + +.service-icon.bg-color { + color: #fff; +} + +.service-icon.huge { + width: 100px; + line-height: 100px; + background-color: #eaecf6; +} + +.service-icon.left { + float: left; + margin: 0; +} + +#loadingbar { + position: absolute; + z-index: 2147483647; + top: 0; + left: 0px; + width: 1%; + height: 2px; + background: #b91f1f; + -moz-border-radius: 1px; + -webkit-border-radius: 1px; + border-radius: 1px; + -moz-transition: all 500ms ease-in-out; + -ms-transition: all 500ms ease-in-out; + -o-transition: all 500ms ease-in-out; + -webkit-transition: all 500ms ease-in-out; + transition: all 500ms ease-in-out; +} + +#loadingbar.full { + position: fixed; + left: -6px; +} + +#loadingbar.waiting dd, #loadingbar.waiting dt { + -moz-animation: pulse 2s ease-out 0s infinite; + -ms-animation: pulse 2s ease-out 0s infinite; + -o-animation: pulse 2s ease-out 0s infinite; + -webkit-animation: pulse 2s ease-out 0s infinite; + animation: pulse 2s ease-out 0s infinite; +} + +#loadingbar dt { + opacity: .6; + width: 180px; + right: -80px; + clip: rect(-6px, 90px, 14px, -6px); +} + +#loadingbar dd { + opacity: .6; + width: 20px; + right: 0; + clip: rect(-6px, 22px, 14px, 10px); +} + +#loadingbar dd, #loadingbar dt { + position: absolute; + top: 0; + height: 2px; + -moz-box-shadow: #b91f1f 1px 0 6px 1px; + -ms-box-shadow: #b91f1f 1px 0 6px 1px; + -webkit-box-shadow: #B91F1F 1px 0 6px 1px; + box-shadow: #B91F1F 1px 0 6px 1px; + -moz-border-radius: 100%; + -webkit-border-radius: 100%; + border-radius: 100%; +} + +.cd-panel { + position: fixed; + top: 0; + left: 0; + height: 100%; + width: 100%; + visibility: hidden; + -webkit-transition: visibility 0s 0.6s; + -moz-transition: visibility 0s 0.6s; + transition: visibility 0s 0.6s; + z-index: 9999; + margin-top: 50px; +} + +.cd-panel::after { + /* overlay layer */ + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: transparent; + cursor: pointer; + -webkit-transition: background 0.3s 0.3s; + -moz-transition: background 0.3s 0.3s; + transition: background 0.3s 0.3s; +} + +.cd-panel.is-visible { + visibility: visible; + -webkit-transition: visibility 0s 0s; + -moz-transition: visibility 0s 0s; + transition: visibility 0s 0s; +} + +.cd-panel.is-visible::after { + background: rgba(0, 0, 0, 0.6); + -webkit-transition: background 0.3s 0s; + -moz-transition: background 0.3s 0s; + transition: background 0.3s 0s; +} + +.cd-panel.is-visible .cd-panel-close::before { + -webkit-animation: cd-close-1 0.6s 0.3s; + -moz-animation: cd-close-1 0.6s 0.3s; + animation: cd-close-1 0.6s 0.3s; +} + +.cd-panel.is-visible .cd-panel-close::after { + -webkit-animation: cd-close-2 0.6s 0.3s; + -moz-animation: cd-close-2 0.6s 0.3s; + animation: cd-close-2 0.6s 0.3s; +} + +@-webkit-keyframes cd-close-1 { + 0%, 50% { + -webkit-transform: rotate(0); + } + 100% { + -webkit-transform: rotate(45deg); + } +} + +@-moz-keyframes cd-close-1 { + 0%, 50% { + -moz-transform: rotate(0); + } + 100% { + -moz-transform: rotate(45deg); + } +} + +@keyframes cd-close-1 { + 0%, 50% { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -ms-transform: rotate(0); + -o-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + -o-transform: rotate(45deg); + transform: rotate(45deg); + } +} + +@-webkit-keyframes cd-close-2 { + 0%, 50% { + -webkit-transform: rotate(0); + } + 100% { + -webkit-transform: rotate(-45deg); + } +} + +@-moz-keyframes cd-close-2 { + 0%, 50% { + -moz-transform: rotate(0); + } + 100% { + -moz-transform: rotate(-45deg); + } +} + +@keyframes cd-close-2 { + 0%, 50% { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -ms-transform: rotate(0); + -o-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(-45deg); + -moz-transform: rotate(-45deg); + -ms-transform: rotate(-45deg); + -o-transform: rotate(-45deg); + transform: rotate(-45deg); + } +} + +.cd-panel-header { + position: fixed; + width: 250px; + height: 50px; + line-height: 50px; + background: rgba(255, 255, 255, 0.96); + z-index: 2; + box-shadow: 0 1px 1px rgba(0, 0, 0, 0.08); + -webkit-transition: top 0.3s 0s; + -moz-transition: top 0.3s 0s; + transition: top 0.3s 0s; + margin-top: 50px; +} + +.cd-panel-header h4 { + font-weight: bold; + padding-left: 5%; + padding-top: 2%; +} + +.from-right .cd-panel-header, .from-left .cd-panel-header { + top: -50px; +} + +.from-right .cd-panel-header { + right: 0; +} + +.from-left .cd-panel-header { + left: 0; +} + +.is-visible .cd-panel-header { + top: 0; + -webkit-transition: top 0.3s 0.3s; + -moz-transition: top 0.3s 0.3s; + transition: top 0.3s 0.3s; +} + +@media only screen and (min-width: 768px) { + .cd-panel-header { + width: 250px; + } +} + +@media only screen and (min-width: 1170px) { + .cd-panel-header { + width: 250px; + } +} + +.cd-panel-close { + position: absolute; + top: 0; + right: 0; + height: 100%; + width: 60px; + /* image replacement */ + display: inline-block; + overflow: hidden; + white-space: nowrap; +} + +.no-touch .cd-panel-close:hover::before, .no-touch .cd-panel-close:hover::after { + background-color: #ffffff; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; + -webkit-transition-duration: 0.3s; + -moz-transition-duration: 0.3s; + transition-duration: 0.3s; +} + +.no-touch .cd-panel-close:hover::before { + -webkit-transform: rotate(220deg); + -moz-transform: rotate(220deg); + -ms-transform: rotate(220deg); + -o-transform: rotate(220deg); + transform: rotate(220deg); +} + +.no-touch .cd-panel-close:hover::after { + -webkit-transform: rotate(135deg); + -moz-transform: rotate(135deg); + -ms-transform: rotate(135deg); + -o-transform: rotate(135deg); + transform: rotate(135deg); +} + +.cd-panel-container { + position: fixed; + width: 250px; + height: 100%; + top: 0; + background: #dbe2e9; + z-index: 1; + -webkit-transition-property: -webkit-transform; + -moz-transition-property: -moz-transform; + transition-property: transform; + -webkit-transition-duration: 0.3s; + -moz-transition-duration: 0.3s; + transition-duration: 0.3s; + -webkit-transition-delay: 0.3s; + -moz-transition-delay: 0.3s; + transition-delay: 0.3s; + margin-top: 50px; +} + +.from-right .cd-panel-container { + right: 0; + -webkit-transform: translate3d(100%, 0, 0); + -moz-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + -o-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); +} + +.from-left .cd-panel-container { + left: 0; + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} + +.is-visible .cd-panel-container { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + -webkit-transition-delay: 0s; + -moz-transition-delay: 0s; + transition-delay: 0s; +} + +@media only screen and (min-width: 768px) { + .cd-panel-container { + width: 250px; + } +} + +@media only screen and (min-width: 1170px) { + .cd-panel-container { + width: 250px; + } +} + +.cd-panel-content { + position: absolute; + top: 0; + left: 0; + width: 250px; + height: 100%; + padding: 70px 5%; + overflow: auto; + /* smooth scrolling on touch devices */ + -webkit-overflow-scrolling: touch; +} + +.cd-panel-content p { + font-size: 14px; + font-size: 0.875rem; + color: #424f5c; + line-height: 1.4; + margin: 2em 0; +} + +.cd-panel-content p:first-of-type { + margin-top: 0; +} + +@media only screen and (min-width: 768px) { + .cd-panel-content p { + font-size: 16px; + font-size: 1rem; + line-height: 1.6; + } +} + +.inline { + display: inline-block !important; +} + +.search-box { + width: 60%; +} + +@media only screen and (max-width: 768px) { + .search-box { + width: 100%; + } +} + +.uploadifive-button { + background-position: center top; + background-repeat: no-repeat; + -webkit-border-radius: 30px; + -moz-border-radius: 30px; + border: 1px solid #e3e6f3; + border-radius: 2px; + color: cornflowerblue; + font: 12px Arial, Helvetica, sans-serif; + text-align: center; + width: 100%; +} + +.uploadifive-button:hover { + background-color: lightseagreen; + color: #FFF; + font: 12px Arial, Helvetica, sans-serif; + text-align: center; +} + +.order-dialog-table-tr { + margin-top: 2px; +} + +/*-------分页-------*/ +.s_page { + width: 550px; + text-align: center; +} + +.s_pagel { + display: inline-block; + padding: 10px 20px 10px 35px; + border: 1px solid #dddddd; + border-radius: 3px; + font-size: 14px; + color: #666666; +} + +.s_pagel:hover { + color: #fff; + border: none; + padding: 11px 28px; +} + +.s_pagel1 { + display: inline-block; + margin-left: 5px; + padding: 10px 14px; + border: 1px solid #dddddd; + border-radius: 3px; + text-align: center; +} + +.s_pagel1:hover { + color: #fff; + border: none; +} + +.s_pagel2 { + display: inline-block; + margin-left: 5px; + padding: 10px 5px; + border-radius: 3px; + text-align: center; +} + +.s_pager { + display: inline-block; + margin-left: 5px; + padding: 9px 35px 9px 20px; + border: 1px solid #dddddd; + border-radius: 3px; + font-size: 14px; + color: #666666; +} + +.s_pager:hover { + color: #fff; + border: none; + padding: 11px 28px; +} + +.s_pageron { + color: #fff; + border: none; + padding: 11px 15px; +} + +.tcdPageCode { + text-align: right; + color: #ccc; +} + +.tcdPageCode a { + display: inline-block; + color: #00aa3a; + display: inline-block; + height: 32px; + line-height: 32px; + padding: 0 10px; + border: 1px solid #ddd; + margin: 0 2px; + border-radius: 4px; + vertical-align: middle; +} + +.tcdPageCode a:hover { + text-decoration: none; + border: 1px solid #00aa3a; +} + +.tcdPageCode span.current { + display: inline-block; + height: 32px; + line-height: 32px; + padding: 0 10px; + margin: 0 2px; + color: #fff; + background-color: #00aa3a; + border: 1px solid #00aa3a; + border-radius: 4px; + vertical-align: middle; +} + +.tcdPageCode span.disabled { + display: inline-block; + height: 32px; + line-height: 32px; + padding: 0 10px; + margin: 0 2px; + color: #bfbfbf; + background: #f2f2f2; + border: 1px solid #bfbfbf; + border-radius: 4px; + vertical-align: middle; +} + +.page-document-float { + position: fixed; + right: -70px; + bottom: 10px; + padding: 15px 11px; + background: #1867B0; + z-index: 99999; + transition: 1s; + cursor: pointer; + color: white; + border-radius: 10px 0 0 10px; +} + +.page-document-float:hover { + right: 0; +} diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/panel.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/panel.css new file mode 100644 index 0000000..a1c5f60 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/css/panel.css @@ -0,0 +1,283 @@ +.options { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + -webkit-backface-visibility: hidden; + opacity: 0; + -webkit-transition: all 300ms; + -moz-transition: all 300ms; + transition: all 300ms +} + +.playground.opened { + visibility: visible +} + +.opened .options { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + opacity: 1 +} + +.pg-cal { + text-align: center; + display: block +} + +.pg-val { + display: block; + float: left; + width: 95px; + margin-right: 13px; + margin-bottom: 10px; + padding: 5px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + text-transform: uppercase; + white-space: nowrap; + color: #5f5f5f; + border: 1px solid transparent +} + +.pg-val:hover { + cursor: pointer +} + +.pg-val:hover,.pg-val.active { + color: #000 +} + +.pg-val i { + display: block +} + +.playground { + /* display: none; + visibility: hidden; */ + position: fixed; + top: 50%; + left: 50%; + width: 500px; + height: auto; + z-index: 9999; + -webkit-transform: translateX(-50%) translateY(-50%); + -moz-transform: translateX(-50%) translateY(-50%); + -ms-transform: translateX(-50%) translateY(-50%); + transform: translateX(-50%) translateY(-50%); + visibility: hidden; + -webkit-backface-visibility: hidden +} + +.playground>.options { + position: relative; + background: #fff; + border: 1px solid #ccc; + border-radius: 2px; + overflow: hidden; + padding: 15px 0 +} + +.playground>.options:before { + content: ""; + position: absolute; + top: 0; + bottom: 0; + right: 0; + width: 50%; + background-color: #f5f5f5; + z-index: -1 +} + +.playground h6 { + font-size: 11px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif +} + +.pg-toggle { + /* display: none; + visibility: hidden; + text-align: center; + font-size: 20px; + width: 40px; + height: 40px; + line-height: 40px; + margin: 0; + z-index: 9999; + cursor: pointer; + background: #fff; + border: 1px solid #8d8d8d; + border-right: 0; + border-radius: 4px 0 0 4px; + -moz-border-radius: 4px 0 0 4px; + -webkit-border-radius: 4px 0 0 4px; + position: fixed; + top: 50%; + right: 0; + -webkit-transform: translateX(0) translateY(-50%); + -moz-transform: translateX(0) translateY(-50%); + -ms-transform: translateX(0) translateY(-50%); + transform: translateX(0) translateY(-50%)*/ +} + +.playground .pg-close { + position: absolute; + padding: 15px; + right: 0; + cursor: pointer +} + +.playground select { + width: 100%; + font-size: 10px; + text-transform: uppercase; + outline: none !important; + letter-spacing: 1px +} + +.playground .options-container { + width: 50%; + float: left; + padding: 3px 15px +} + +.playground small { + font-size: 80% +} + +.playground .cs_color { + position: relative; + display: inline-block; + width: 95px; + margin-right: 13px; + margin-bottom: 5px; + padding: 5px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border: 1px solid transparent +} + +.cs_color>div:first-child { + width: 30%; + height: 12px; + float: left +} + +.cs_color>div:nth-child(2) { + width: 70%; + height: 12px; + float: left +} + +.cs_color>div:nth-child(3) { + width: 30%; + height: 71px; + float: left +} + +.cs_color>div:nth-child(4) { + width: 70%; + height: 71px; + background-color: #f1f4f9; + float: left +} + +.playground .cs_color.active,.playground .cs_color:hover,.pg-val:hover,.pg-val.active + { + border: 1px solid #a55ee7 +} + +.playground .cs_1 div:first-child { + background: #147bd0 +} + +.playground .cs_1 div:nth-child(2) { + background: #1582dc +} + +.playground .cs_1 div:nth-child(3) { + background: #2e353d +} + +.playground .cs_2 div:first-child { + background: #14a5d3 +} + +.playground .cs_2 div:nth-child(2) { + background: #15acdc +} + +.playground .cs_2 div:nth-child(3) { + background: #4f576b +} + +.playground .cs_3 div:first-child { + background: #353d46 +} + +.playground .cs_3 div:nth-child(2) { + background: #353d46 +} + +.playground .cs_3 div:nth-child(3) { + background: #353d46 +} + +.playground .cs_4 div:first-child { + background: #fff; + height: 10px; + border: 1px solid #eee; + border-right: 0 +} + +.playground .cs_4 div:nth-child(2) { + background: #fff; + height: 10px; + border: 1px solid #eee; + border-left: 0 +} + +.playground .cs_4 div:nth-child(3) { + background: #39424c +} + +.playground .cs_5 div:first-child { + background: #2dbe60 +} + +.playground .cs_5 div:nth-child(2) { + background: #2dbe60 +} + +.playground .cs_5 div:nth-child(3) { + background: #f1f4f9 +} + +.playground .cs_5 div:nth-child(4) { + background: white +} + +.pg-footer { + position: absolute; + width: 100%; + text-align: right; + bottom: 5px; + right: 5px +} + +.layout-toggleMenu__item{ + display: inline-block; + cursor: pointer; + padding: 5px; + margin-left: 5px; + border: 1px solid transparent; + border-radius: 4px; +} + +.layout-toggleMenu__item.is-active{ + border-color: #a55ee7; +} \ No newline at end of file diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/in.png b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/in.png new file mode 100644 index 0000000000000000000000000000000000000000..c67e5b9e710882f52a40f7f6e1d3431c09fea6e4 GIT binary patch literal 6172 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

26~wF>?ixo!s6 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 F^*?Pz9S8sb literal 0 HcmV?d00001 diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/lxs.png b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/img/lxs.png new file mode 100644 index 0000000000000000000000000000000000000000..09e85eacc2a99619efc1096741a3774cec37479b GIT binary patch literal 9872 zcmV;BCU4n^P)w(EZ*psMAUL&X(s%#> zAOJ~3K~#90?VWj)9anwlKlfJE+xqpQt<{oksl8!gC0GI+BnE@YA;A!4j*~GV9!SEN zb&``g%mn4koH;X@B@@VjnIvaIGAA$zkPtSHF(wSg5MscKu(9O^Y{|A{w`DCYwU*xB zQdRfPAGhkgdhgZNt?qUU`+Lq)KULkjb*sMjx8CImtu-&<#Rd67H{d0#K3*dIMTnP3 ze-Yv((qDvliS!pC>=(KL%Y}VoYy$QIR{{OYT>UI?7ScBxRDbkmVY|m#zYlf6& zL~BY~GZLH{3O)b`(Y{8&6oM%sK)?iox)e+Z!ITtCTu6IZW8|+1(l3N;ttq)aqrPHP zD@L?tlz_|@ry}w_JR~yyAE`i?^Wz96q+nbM#)0}`+sYatf8|NPXZZJkKU$8e>SAE} zBO4$7vsu>lc^*4_#SWzz4bOK;ZtF{w&u((#j^(UpTnG*c!65-ti+q$9l>Cb-PFKj{ zd_%sk2E)v%jz`DMjL zMS4lkmW1+4(LCZxN_Wq(?her|GXmUyWlj@0WNg>(PC$#$cuG{K|Om_YD6rh+7pF5^tDZUX~1n z1;CWt%6}Soq~lzc?ar{vODv<4%k&3Xy+JP1I?pI2^uLr$Z;%#Ob2?vn) zNPLFW$;1~P{(p&fc@brFa+#QR2^g}3{xw_bUlUMDdCV2H^D9F7jNH5md2(Yv*MRNr zEEB!9+d&NeO2H1t(jT-0qZtpmB6fb+N#8fd&a?LAqsv`yFT}+n-AVTvvZa2vE%lzb zr;A|OiCAZnIANVqmK}I(Lsbv=BnP-!o(H^atsQcp6TBn9}7o57i;5a=PA-koh=j{PCvH3#l zTPjBUCxI?$ikuH$@ZS1o*wOq)RLrACNk~G*=?kkzFk)%K%wt{McEP*=(C=eEuMgr0$G)uIoDQq;?Xg5&fj_Cl-I&<7# z0J|UTK4Us!kmxNhBXjNmm0F|%`T!1;mS3CwHG<=wm;g9T;fHpaS533 zI^IksJV)I9Q-~Z~bYjt@XWH=>71siPut63BbK_>0mj&aasCuG#>MUP0 z_sE~o-V5B7r(kZ-3RlB&G&rRy>Bev82n-+JyyztdFMAtA`c-PXiUI~FBtDzSkOEN zqG(?1$^UDPA%dRo8-geA0ehe=3GR82WjMbdYR?;oPC796qL%| zMeyg7%UKmT{{uMnHK@KUNBJr=&zk2Ld^J?BPVXdE1?HcExr0D%(jlj`=OR5#${Q{> z2`F{ERN+A5G@Q7-okf$jd3aTaQ+LtI;Ry+L6%a7_4?zbA>anVZ^r?qI-ESDx8mw|e za|E{}n!ib$x|D$+Qt;pE9JB*V7Sp`SXB;(j}3y8oYV)x41db00C+Kg1N4+A)?ZQ7Z<+t5Eo2% z&=z3_rX&ScCD1g1t9aaD> z>|)7bwC*wW`V7C> z_~gHwWmEl0Dn8Ao$A@WQh!);h#7TT4BWLxQc-x9*3tYLcJ<8^ugQx#{kdb>2l()5$Ge~#~Qb-e)`3FtgM8w8xADlsOhSKX2(zK;<+N6l>fs7E$GM&twGSj}S zVs`z_vnD+)vZp)1anzmffqj@gtAw4O!(=ghj&J)RA1!xb7 zBZfSk;t3~S@0;n?-PtiAjo*>=2}7#fx}ksj;BiEy)=Zo*UB74}6*OgEvkuXZ2ru1B`d$ug9; z8|hgx=>+z@9N70G#+FV!1XDlAaj`HC+?j8|nR{}U?>ED?dFSg{>1#l{-@PRhH#F+t zG>-JR)az*Muw}P>?`)DGMM!#g3kZ%A{*5`_zDxUhVHpV!R<_5S7uo}70~F`X6fc5~ zloe44X(V0ywASpUmbZdV>d{)4msvi!kmw>K{BK`LkIvV7a`7FU=9)R9VWed{TK}X- zd^mCN$j51^QNL!S%Abev|3#~-Xs;bQ9s8SLoIQ-wPnmfC)HmSleV|>ihs+C+k>pA^ z^crnZI7y>5d>bToLb5s@(1+5c;Lm~I2&QkPNuw~=sJd|?Q^vhp<&|qxy46Qkij^?0 z(fv$uC0nOWeMMW0%o986)W-kp zs30>JQR~Ws@-PhF6ih1?fHIRZy;`gk!?&_6VMHV7P=fdg8M1R>i z>0br*JtRFe3v-XR9k`W-kY-N1vmT1W3CWvCr;27ClW;-hQ<|E{MLP1@^bGGkseu=g zc>`mw`yzuQtB?#3mbvfgubY7&9mMY)Wkj%6e!z?*PCb-PVmL@-SK)ZztfuYtBSf&! zBU5Nw#Y3dT>Mi7x^n@N2CHuU!tXsgogbW<-du^g)orOg$V2mX^)_Y$L1S!k%wm>o# zkz2oDgyEzQ3rC3^=@QbI9{0SN?2$PXYnxAFB3;T`_1p3H?QSNWgy-QRzfF&k?tG(d zOGV&KBUhR52#O;n>{N9+RlEl5AR1NVniLWGBa12@gu4k?EZHIQNqUBK$KNoTk&9;8 zAYVoI(awD zK9RgoGx8-dNtS?|lAbNyy*E>VH|_xz&=p&U`Sj>qF&&ieSnRM0&RZ;kdk^evueu2l z&g0WfC|?3Yug+ezI{%bOO!d7im{*^&KcH1H`G4&J2}_&0Guy3yvXS4Wr$~1X;j#$x z&%jgvnbylwo_QE=4i0~`-O4bu6PDS1Dojy^lOQXXXRCK1P28`;mIc|jP)$n5)FA`A zx)}I%S~>P8dZs|9Wbj%cYmi>eT(wFL6VS$D&1_!peH=_EkSimHFul4t*?COZfCBeS za7;&z2VqJpsp1E#RV5vp4fZt7Hfhz<-=ZU_q3TAh&OK$OHH94^>t%N%oS+yb-72@o z2!s=42~#?zRi?G8ge(NvxfFV=GTHh0ZePp5Rq1(mSc>-^e$VV(g4h|SLV=VhWiziN z7EqBM2p_ZsT7XbAmCZ@tK{Z@PY$#jO*wya$5T_%WFrVoIw0nuz=I0L3=mK4t)&UgcXgv$cVKAz8e&#~uB z9N9``|1Ml!(kFl&sZLz#i!?9&3)5Tp;><7&Eh!3xg+>FXeTPRIRUW7fvZXr5e!oIV zC>+eV^OUc-W46v%!{v83RvEFab|ZY(q)YpEg7Vw(pMuFoG%&a%n27?6VNiZ-t=3#2mu{XZM*3MB#G zEEd$RiM9J*VQjo`pg9pCJqXeH9MWkC}xIL)RORJZ<`uD8THGVCE;V>CMJh zNi_$KN$oC-cg`E=E*9gx`^zWkVghupbVqNP1nKicZGg|uY-Ygnktsd6AQUB`h>Kt~ zP?3TuUvtKH@ilyJzQKJ(&4((As%}PB!Gr@AA_xP6?Mj3nbc{R*uHX2kU_3tR$W`Fn zezU7Y|4!Kaw(O8i)nMv}u>OX88x7TunJ|xd(na)dMDQBDt6X{zNBS&X(`%Gw+=@zc zoC6WZywD&Ncg=0Uhg8DzKm)b_yJf@#kJg)fYI2ef4QJ0XSrYtt^KjjpC#X8DXuz9I zpZBgct-a~|1><<8k>1*TA^mycxR_puUAEk@)+>(m!^H1CF(pLgx5p!2Vw)xu3c-D| zn;2_U>60syN*%NvelYz!Pfs7^>Y>YxjbBb!CijhX9|Z;DHtp@h61{h!nelD@@a%S;b;}IMl!uGKQuuO&&C_!yBh#h28kaG% zG#)`x=;T)tLN=?tyVUvpz4z@vs1YhAr=EM&YM@PG5Enw%<9DPW@2b__W@s^v>~iKJ zcW?JP#l!XW9BGyrvKCLciy+@Vu5A=7i{rJkjL)86bp4e^>VjE9Nk7){ILLGc&g3y=#=RIMl4*tTgFDmVl|o9G^UVH%HEI=Z1pMI-%HB2%M#hl>Df$HM~SAKiqvF ziS$@!&e!5GEBKknUWd+nnelAS`4099ze%kmjRixv2s)S}EF5W}wBU@_r09T_#unR_ zMagn_VCp#E!=fMruP!^hcU^_56c-)w-8Ow{o}`S^gWU&W4P0ROd(?ujm;k0iTOM7a z><4yj1tR4hNU89eHp*`k9)$oLA!6H7k~UQ-um#*Z-{7y$FR(hTUQTFyX}1XX6;reI z*!1gc+;*X9UQLf$08mPg;T=P`N73E{TGtT*b~f$;6oa7;$0;V z%%1t{H_T6c9W4ZwJ&aShj3=58Qp>1mO{|HC_5djn{uP#=%ye{r#_o#MAApN)R z+)GpYlS5ZL6zj!T*1!9S*{QExiw4g{0tbyFG%_+4Qd;-haciY#&mOsc z^0p)9KY#Tr54TSAsD$@_rSDrT_fPK>gy4wlbHel2mWmgON8BpEzp#}@yb1-O=odbvU`RS_X`yu0gkAcX zxKOQwyW8%#zV%&l?6bf$U*ytyS7{cek{++6)LSn38bQy3>4U-SfP@GR4cR1^gzcqCm;) zH@q4qR%2em>W6J{%eoAd7W_?p0}U-G3YFNbLg}iB(!kB*F{cg$-1XqLJFZ7^>2Cmo zoNLS`t(8oa_JNJ@(hi1rAIZIbAHPsN%kOO(=ObH=@VduOQMh}SO3lNw6C_uFkD#Gp zUTKsKN`iBnTtB(t%7+gSF0md|rY z74eDBGlVFXcRssVDGy--OxDhtwk4N~4c|P)#L)1+eqv$fyVoXND1b4q%wA^(8j^Ke zJ#PEuIX>}s1H58rlE+nr>SdDMFK<#%K4r`0-g^dk>(w*t+5^|s`*`B^8n1b6k(;lp z@_5DPzdq+N?L$R^l{UnifV$Rfb1XivzK>BS2w)a1<&nvj5Dd!1v_$$GZC3c-=eP3X zMin2h(O8k98W?K`zB#{+JMB#rN)0NGpV|jY>p%R}gj1jY*!Z)W&2NOK&e)V6uVH;>j(6H8dHa^*y!z|{))9Es$UHcb zdwx)3x~AB>vj|Pi&Z^)em)qPhAQ`m4R~pX|Xe*w2P45!_Ii>mez9OSVCzw{9mvA!^ z$O9%+fkR$}A9;No@ybkTyLG+=p*Y?w^B*TK=dnhWKIt6zxw*DEg&Ozw|lb zJ3KenkFGoPOuY_J>VNZn2_Ac2pEIXJ-9txX2EyBvQ?@zrnD zc>QZiY~F4|-L&$Gvf$ruw^+btY`n=|-ZO){t3qRgjdV5215bmrf;9*}xCQWiO~ci^ zzEa=~eMRsWkvtNL1#R)Q`Vc?#DxB3e&0r8%0%a82ESEPqGwiWv38nrs(<7Yr3k*pw zm+>eFqd^+=BEnMGj)#tfJhrobp>OyPzMXJ+rj!F%yWX)CH^-{b+WAi|RMx+L5PE+a z%2Q%upnCa^xv6hdJ5C7DuEj#V#CPY`@wK^4oT!%(u8mhW(l15@_EtE4zhvRG&Hl#+ zdF$S32KyBM^D`Ui@3(l*tyP?0aSYIMdL03mZFW#k*Ess{0)yL%)D<{I$zV|-W;|YJ z6}fGDA18k3ve~nE*A;#IYPC#)V(4r9Z6CitBt#{*uXcjCwcasPp{wH zR`Wt=yoN(#zD%v@aKbAfgQ?C!gZ3?&3kB+@N~kLf%->MpYu~M6OGVQYeEhGrVmn2C z=e8=90ZHr>Sp_sT|Lm4^Y_Ce3JI^uv&GUS8i{N9ImwEYp7B^93dsEW~HkV!NKrM$#51Et#q{7vbF|SNDCWI0~x1P1JP{Lg(A{PpLc6x+wFRU{Q zHZBAjJl6)bb0S5p-=4>ohp=|PV{3M)2x{j)Ihmy9eZ}6sY>NN@1=&eNK~&Vxy4TtB z(|2rhn+nf$GBcY(m=0o5`YxU`kHaq=alO+)0|^QN$&Id@en;y;?|2a z7mE0vjq)v&Zy}ZBOtZ*Aw?gRx#~!qjC~wHyc-3G0xwQJ?9OeUOk6eG>V(MJvy4@C% zX3R404t;z0(obwU`s9bN5u`2O?S!sL>YGcW-BaaG|kl%`Xz6F>i~`oO2hgg$?v>xfOQ))2sf?Zv*#E1(oBt- z(l|ok2(v)Ljj_r~Ni(Luj3a(==pX*&yUTW-~ z{k10REQu}JPFmN-DM4{#$F*Ai0iY;`w!HJ}{Uh&tIN|i|0SAl51+_Z3X>6Df62EN` z#D}nirmiF>y+XDv>3z%kEfUTIR+opeB}rTFCekwN%@ zV`Hyh65()xqz6c}DN0c<48861Bir6Nx0nij1nVuA%bbSE1V!sJ8(-}nTE?mY18}u z?DEpczdC;S*x$xSlCvLVaKJ^HRRirRg)1D(K?_3DA&!5PE^<0cA37_sqP=X_3!&O zzxR=pGPj=`d;Mgw&t3X}Q(De_G1xc8P7;U*vr+Aas(!a6Qx;3aEthIR#~fRHJr`6a zt9(rRl8$x5^_h6)l>D^or>-x*{bSd$WVPOE&vKCt*~9~Etm>N!PVlSDtyc7E;kdob zJI+TcNF`~x%Jj4=tUJ_EaAqL9q=r60A zq=^5;=AS0%J~J!so}3YfGKwAm9*kR(v>aGb(nI8x`gMJJPo=1D43Dj(bf@lzw*t~V zy&&$Lm=gP6DCv%3RY-??!~+y;hSv9~8;gZ>5C3A3?u7=Aot%>QCafLr#)=aTt4KQJ zCmx{aFtn~u-B@ziwIs=nk=8uk_i{=1BFTnTA{qYyMVlQ`P+H5< ztu*y|lS7LndqwSc99Et55Q~v|0NbK8P}V#8%X*KUl+}BIq}%nGm|hV3&(4ZNIc#=0{; z^bpHM{u;oVB0I#IBt1lg{HuuhUH3JLSZ)_4b4^F&8+(U2a+8tDKR z712>#l%&UDg*(DUOK=>1YDj+x`LVJSw_n1V#Qz5p)D;9$w(EZ*psMAUL&X(s%#> z9yduuK~#90?VWp+9mRd;Kh@p$G4GK^j~NM}5y(d3IXt{Zn6*R_+j1PUBw&o=*eiRz zUi?aYyk@1SaFBl8$zzH0CSPSjI z@d&Z?kFvmf1uT}X{J-*TcOO}3pOWAN=?Nj8`Xf^a@j)T^JHQr(I0^WRh4w26PBiZc zAzUs(${TAz3m9BLcjkl>N>2b|>*b3C;(8$EJ6u^Pf98tc8q%+Mj-|i`U@g$qWb--T zl{V3JaZ%>Z3!FRdZhwwT(&w3A6}t8~FTA573m*@jNQ<_%V~~DRaomu;07Tc}(ef=D z9qe@Q_);;r{+j3b9PkRT_1bedbgX?#ik2pQp^5e|>}*>)Du>raMCk&~1~|`&_sv0aRmZ$AF1?ORuMi*|IS612c%NFYZfIDjkMB!A7wL;F%iRfF*Ct;)`tRBe%US|VIUDX8OOQq^ z#6mq~yXHC00ItxD@7QGXlX6{gN?zzV^oPYuqHaIoD)RH@5pL`G1TIdfU)}C<{-p4| z5i83RX1lRdm=tyM1l)P;IqU#1w_ZLV;XDDS0;_=)zyL4_{H?R$uKN<$jl?lmdQx>) zO7u>Sxtr_~>!c(b6}MUH_Kv@l{uyp`pIwC``|W8ia|%w;u*6QQOFSe}Vm$7$Bl3+8 zU-0ygi!VBlECJRDcq`DMh`LN{z5K^=!(AHA#N(KfoV_nWYxYDK^S(zpLbEFdqam+~9 zB|Hh)(0q0Kk53z;IxZ;fP?1BcX#DpArukj~{R^tCWeF;+%n&x_t!9McrPUDdTY5 z#LLWuVRm+z&+yaqO%%kWPWEPSs`-}3HmCnIpAqe+L3MQBOw7w73LV1pIXQTEpL_LO z3HM0#24pi~k`b=F7AP50I&RGv3)>X=$&xR$Ap+}fN)Y-W&^Bs0tk0BGT ztvJa%^Ox^Tf9l~j(WP36(^TS{MtU6Kj!pK^9{1|9=6&}WN7IOJ3h6q8kGU%IF>M)DR#()@e9mZw(l>;iaBQ-< zQF)mT;d51Yoa&RP+kd{76$s+jO%z3rJ2GF#70Cu|OXSJ?vHcfxiQc+OEhPP!qI;Q$ ze$EhD<~lek(rZnPa^gj&NpFU_qv9l0x8F{WT&mTtPl++cjs3Cl{OFS>ah3Dubc@Bx zd>PQ+o_Dqw;l!VNG|l{+NssEsbqSv@brXzJ7Y z7DeYbP(GF`hdN5`rU=uC`}f48NA=_RoE%g=B~y~?9rNNeQQfoWlB?TqXN_|nMiU-S z^vRWc%=s2=q7xxNVq=Rk6_KaF6h)>ei99xCT7X5-v8TOkt76 zB270-=x`U2rkzgNOP0$>lRT1mdn+=&-pJD#T1iblo2t^I0q<+JQZ1{ zEJ{e}kRnT3WXQ-YU1AX{Ih9_P(nbe8Vkv3T#fhwWy(>bOWBo7P1(!*yacEOAHsW5@ zKzNYc;IRmTm81%_opECy6Xre+ny;|m+R3=_1|>0#t1C`P9 znYG_ujmi1^3YOy z64Eb4(U<$1bzODGsW?vEuce-3NBVyDnL9wt-)de7taRT@QA{%?_9eOwnn8EC{pH3f zJJwqpx4qfiu(wO}c}@PdYtM;SyB6tDDj(bLUN*CyZJyQrhP8ti()Y1D^-H}44o!lr z{oAaOe6t{d6~<}Xhpf%dthe62w{|#I?Ye!svM(>@Wq+l}(EO|0<*~N^!%L~3V~die z%guwR{VSoRXcxeK_oboH%I>xM+?|j7o75k^&@Gn6_U*Ask5c*QUU!RQGdQ2>9y4C& z=WRDIYVC^j^H@PjN$tK1A?n)z@6nL5R@L7Pb(ONJCUhQ2-f% z+g7az3qZaEq)Dp0%v|#uBIZ=$n)kJ;gQaQNIC#@++QZ@pj}O@E7%IPqSFNXO=S1D; zxp5>dX8sj3zm58{ekXu5ZFI;k4v1kU#c0fZe*G{`3Xle@e8b_q=PNjdpp+Kmhu%v2 z%G1bAjv{d}ytOqmd93$*)>i>S2J#q)BO0$OP&_1!p2t$8D*zUm%IT?%y9wbAA_j6{ z1Gq|w-tiIlv(4qkiW*?B)lxGUh6o$`^fuJTbzkQ5`soALT&#hb7ZvHFf*q2QM zq#GbjICq=PRsUR~oEA7Hq%wr_Fmc2%pJ816%|0?Sgz;^>4yB!fTIzk>aB___{G!{qyBDnD@w5Q_RMl zIp-_0Zs~?CHdS&M)x0a4hjLL4&9}N|uG6)jF#MEtFOQpdXp*glkkuwW-)-TDa<#el z5|cKi9S`76kJ0t}Usn4c6K=>uMA^0>hk%C^ZYnucD!taUH|*wA&dYveZO;~>)$RSB zi@J5})D?!Nx&`o{^#dL@|52ZC5i%x|AZ#eCSw-KvD-co!8Usn?wI`Xp>za8{xBs{) z=xs;2n6gVXiVthvmCZtFilGLlLmVOCxVlo*o_G7No0AQ>a=sOzHoK}VFi!}?a_c3>(Du!cX8U!;w8UX{Pnx+X|S zcI`!E*1jz?eqrZ>Oh0p1Q`GG*k2Il5uj5ojx_bIf(mU_!MrB8Fofr0JK5*Rw=HGKf z90(}`H3nG2hvk>(6g>z5(_$j_nz~goKL2_y`7~zdlF;jNPuxOfUnX9_}Xx1 z+#YlW4HX|Cm8R{icY{z5o22V-_}>4HbV`jj5~#bOvKj86BDp$FwFYu-g??Ridl^Wg z%4Vs%`rG9m^M*vrsa9|b|B=6utj=db5i&7ZCd-iNg~eCIGXKhF4r ze>>a62lA++?jR3s#J>)%MS9($#}-w$cl=l4u|$g)tAu}p6zMuU1#;*m6e>f?vpzhh{IBm>3Oq zrp2Td<WX;XOuCHz=sSR`uWlOiPVIMEG)d`#>I_Azs@scmPz*CF z-q6VsD>#);@NI>i>Jzb&%%i3B+C93;AJ6}`^_R>#t$;oDI@7=U*__o~uk`rYB<;zW z`BrzBQgqbq#ec}S9UY=pa0*xRO@*D==iMfz&%>y45urYNdFwj&QjAnI7e^lb!OU!3 zQgy42M?tT7cdARH=2P7SuJzlDQul1SE_=n!*t~d6di}MH&%4`1{JZHhi1FFXc3|}m zM4E64lN@>C_J*?2QMW&>jK-{-Zu7n%>LzF>B)$-^n-?h(y_f3%YxpGJ4pg*Rb^GmS zWxJMY>h_U~@Hsnp{;bm>7=Pv-+;VYF>h@QXIB1gIs_LGN^Sp?Dg4WM!J}JKKyS7o? zexG|qA9`=J$WWjCes-PpPJ|J?BvDoh9NGHA#Oe-Kk~rv*uA$0?N)ZU_+97BsBz`ch zJrPa&a!%$`;@Vhs`~6sMoP>pX{yemd0yh1}Q$5QOnfR}a@bcU?RUU$vWe zFX32K`oc%6ZdDCesZt2YqnE5`Zk+0HIs6Kl&UPBH%E zU5V7~h5dPof_|T_qsl;d=KLJhO(1@lDsvp6qId*aCHy-zJ0a@!RluNM-Exsm@o1|u zv;0&oRwkZ*AkvOf-M(-f^lsU7Yh6eM@G{VBb$jXT6R$KZf$F25Pl#_~3K6aDfWQ92 zTW6jP8bztA%FMuNgw4hKVNZ{f-@QGNx`U#Mf)?q9$#AQw+i!20@w&P8MRE!MNqmEh z$b>2-Ox^xC7nqxBb9M31QDxgnr^gQFfa)yWW49(!w-+u;F&t+;k;u7O-=Bri?{ zejAG4br}pHZVhLWp&beI(#OZmuhStqB9#(a0es1qmG2RpnAKz~$moY!L6}o zsC+(EM1O-In3skM9lE@e(=a>JFsSP=RXU zGsFeFS8Sn|C83IovZL}@2>1i*gGAl0OVnwFm6z2WzObU+uuJYYPlVbDs@og4l%yDm zGp)B1g`n7=1VB{_{lDu9HRO0$oVs*;*R|V+>9+TRaLHT!Oj*kjLL|1M3afnXH&)Us z`ZyxPKiAb@CnBwM_c96ybe<6u5ABI8OVzt^4)IFYB3)Qwq~U22YDc09F}4x}!h`vT zIdk%d3>2QF-93cm7BOWBqqev~Vq%L7j*+Ec^l`B5Y+mZQl2^MnN0S@ngW~vR>k58Y zxhbS{WMo>waC%Wcnw;a5rpWKxLB~mFD4TMX{k%IjrRNAPnaYY`G3_Nbzv}L`_wl<2 zzsTzRL$o`in6iwBD4{etaG;C5EGs?F`ia{qntkl<{2hL={J$}gJ|(fbgK;*bF5zDL zR;Fa*cU}Ci9>)7*A6~$ljk=+~l^sdu5Yw}jQ?R{9X6iIj^B&ICWVejYk@mtyQ@(@?Ox{-nW zQw=^7;#=77E7KnhNl|fKgdMAEaf0kf3M0FGHlqo5Bw^oot>aWh`c~y-rWp2TC@k^1 zOh+7_u_NFQ-}n$8+5K->Rd^gr7HQ5l4id{PuyXnrynom4@cXZScqZK>Et2QwdDaG2 z8>cGMX|NYjfl?j4c>C7qpft9R&{v%UzYF2_=yjYnkRG}#k;QPc)!kd!&8K&*=d8)w zFs0tt4(9?>mRNV>Ha_<2L6#Ms(^hxT=Z|DRLt3#gCA32O^6JrSb}WiqGZ%zY$Wfj+ zs8v~~9X07ePPJFg$aK|UGt?~voIP<1SHE@+iz_d4Y&K|-bXN9p<;xdy-stt{=Ed*x zGGl-bWIkHwuS5N6m(a>o3#ZyT5vKl@yslkl`t=t>E2zJ_8nc!Cc>}^o&jk-iON?VO zadM$);+|7c%@4rEhrh|j z(XV32rhhk98v>WJ58Z@`!$T+E5KB_<*yY&|vC3M_VRw{EQt#9z+dC#KebPZv&W+Yr zN}nk>?1G+d`+CrR@TP?$ zK2|YQlQOxayGtqW*JVm}!H_l=zVRjcYNL8+Bu-VK2^{yr z!Mv;NnAy%mKDy;%b-|?HjxX&AJ5=RL4x>m{-mlwfv0Yc)ULjoe#)s&%lYP7FSR!K| z;qALWjp3GK)g2uC)uK0&8)3)H>V4AFgLEoX@<(RUB9PV_CH-10sJpj%%ltC9I-tY zGHMT-bBVi8S2hoh*Th4px~pNyTaMgFUpf9IgoQ@dKE%4wf54CxZFM)03)EGBIy zwRK+9?YCp5+h&bxz^#;UDuuerBm@*)F+5TZosdyarxQbZt$Em{I#)>>52@8XTf^7q z?qYGd^_zANmYZkQ_>VDbvuw>&x8IJL$)dAB(t~T4k(E-zz;R#EcqrtOZBd*2>!hr# zF=eZ&_OMZIN)}j^e_X?SYhm!n-E@@pG+o{PI7TXyMCiCq1!-662ro)8ynhZV2MyAr z)Lu**_lMQ+m4zo+UJUDQS{L2LT`VfTm{{Gymv`loYhU@8=?t@1Yru7pt~2A05b$c= zxIZLzq{>16fs49tH^qo!1aIN0HGH7>EbaC|P4lgVWw|FYq?1V95Up0ZT|u*LSn>d6?0Q8{Rm9;No_jB!6u^w)4hI4mo^pkulv(Ko$~j5F3$b=SpDr@@$g z@jLF%l@f3NQ7I|zoHpmIa!B^sP4#@dpjb+Y``c`JnU}eCdyJm)YYYB8lewZV_be%A zno??MxZ1sNK;8a0>iE!}ZYN`x5Vqd#RVEhc+J|@dmW=yLZs>PTVpR?ao~K8tJ#QJ? zT|*3eneMa?&|xRr!>yH&tsEp{kJl*`j!xb9;*iRKbgLT#$NkmzqA`S^;ELf_3uf3r zNlWFB`~$m6wF69~%-ar4JD(eNL^@Mm!V~TPm2`F*H$mUkDll=_lUqu$V&F=}XEa41 zOuf2;@Q>6j11c5Cq4Pdf-9b7A0v91Hdd)N3>>+dO>ESQPXsH}X_9<}Gzqym)n{<1dqrQQ5Ph^1}U?Pmu7-5|n-cs?X=d#fv)LYtCG z+WhI39`~g>;*ZC_`G#iYYXfI<7k}4fhQ7I?-K={^M7mdtuG`Nc;Lfmk-C5)A_jJ1P zyXl@lEY9uV{<6eaPFpm=JhapU{CP7r@IxTuT!F6!jz zkkfb0H0wdcu$qkYK(kj%RN22fP&}p6xbeyp#Lo#agl`Ka9AdktWTdM{o1uM*1I5!i z#1DV3V*%DWAICVqQ$7)@g;?z^N*{7Xa> zWj~$-$w&{`LOrT~hpOTS+l?EqIzfCSVw!Y_>c4asdOk=85D)kgQb31zL%MH%GRNf)PaB!U4*Ztj><;wftj(E4&iVVr0bye5x5P6Jel*bSh(vJ z8}4RPG=8z!`wflHrd7vO&%0yo#H1B!o7t0fK83Jdk&M4yFz??}G~(8TZv(dKJ}OO$ zc_rOL)RQ?67G#&3&V}8E+yokA#)V_H>WDn96ZQpEl_!XUW#ge;dE<$Q1rQ$Yy!M=< zAE8I#n2-*7!~?Vm*}L3yH+2|t2@6BQHTrBnj+wgsSTNEdx#~T17_zs|a@Td4a$Q!)!G%zF!4bpbw%ED9Wb90!Y7fU; z-F_@6=^o}vK0sQ?>|#p}cA4&A)}TLYR6hpXY;_l0F^U* z_-OdsB)Vt`vOTmE=^mOzehZ+b$o9~ZqPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>DK@LeoK~#8N?Y(z@ z6-U-Bd_T+k&wcKU$2MSlJkb;E@fd8PNydOsKm>t=0Ffj>WRr8wCI@41zy=I98B7#8 zDCcvIPR?n)YgMa3FpOtB>HhBXu*Ft&SMKV)YVTcDE&dn&UP`y}Q}kD&pQ68=<2gO2 z{}<_B2B5b5Bq=7<8a}7z^xunq9Dv$T+T80``pF~{)i%b;WASr(PXE2=?+4HmWCKE) zC24V**8+~s&*?e+51_vrKsIEgZ_)%#+5jg(ti*X8XF`J93M9rn2hnr-pFlqhpjHeh zuwcQT6hRXYBOM7K?sXy9Tn~R^4Z;nzh}4st8j$dLfOzx?5d9#Wo@4Df{mbZY3Ddt; z*d7C@wO$2}ns_3P+9e)A((6R5z6#Ouy9nPYL$K@$g4eGgD!z6ZVTQrmHxQ~UN6hI! zDjX*Iq_M0Y{c96EzA!h>={fx~Bq92t1*^Z6{^RMdYM?Z=hY@&Diebo)WJ3)i_iiJ4 z>l%_bt{`>&5>nT`CtpUg>=NQ--y^}e_;muQ>?*uBuftn@9|@0()?Q4Nn(FlX(IY%@ z^PHa3KSO^@n3VQ!0+2i!Q*CP>9s!6xO*#-ls(6Ho&rg6kvY;-5ZEB)B}+S>rMS-TlW2PdV`7K)Q^4o!10S`o{O znt`m{YD>S!rb*pDrynFUZqESHkLCY))GBC(|4jgTRHY4|R1)b}7_p{$1aIA>d3J>W z5m3ki5do4iVEW#GDlNb$PTEP=(nw^ z_v9qOlcZKkkkdDmpJ@b8+AJ_!MY!@IO}QW&;e-5lesBLE*#iA6mheBpt-$zeoaFDe z{5Z`PrN?>o^PeL7dHxyt`^zie<0rQGU-ztS0Ay9Hs?G0M1d-ZmL~dTAHnD&pfEaEC zj9~)Cm}{*-k_JkP=^x3w13_fUUnQ^zq|mK0BwL!<2+c#&nrZMkk*u-Tn|LhP{|wvp zJ*(a%P4u?+N>?shxGfW&oMJx1GV=d5^tg?-*H7}_qDOgK``5P2lXWQkj{(SX@HMn4 zug7Sgs11;(%r>!Ywmo8Fu4!@Myv5getuk6zP<{d{OfW@jDgf;znU+ZZy65?SoUHNC za8LwHjCEy;xp^}twBw~&+NO)`Jj(I-$BNhcwcc?nvl+3K$4X75lLVL*rp;!#n7N;R zPmk_(VJflc>3oJ-%PX7eHJq^8FwEXj=xydNGM~Z3E3^um->ORac&8pFdEJ`KG+m4J zbRs2~C*>tw2XpLm7^a!7dy_ZJd+og`k6njOil{vE zQ&^3FvZM_P-3l;BFi)KIB-oC^nCc9%Yn<$qm;Y=4nnFfMt@kIk;;b9JSIca)qI7D- z2(bF2dgJVK!q0oF4J6rSGDap?wdJ9Wc>3T-u8+w}es*)e>B))fOi+LO5~`U?OV;sYe=Y7i^CilhMq zO)?7p)7(}YC2v@Z3FcmDTAgD#n=Q?Bf!c_E(A}FzxEk4zc@>Z7ZwlEDkX`m^!F?9B zP5&|FL~ZjtZ8|)Q{+>ET%4cR{3P7r^oPOtd#5oDYuAVWRxN;Hkt7nnCe4cz338qDF zU*|iLX?z+fa-8|%*Us>r*?iiB@oVQe5t46QK(e+9=}^!TQUk8m=MIP9KXVcd`?jFz zz(zEFx(#)o?uFyrcf?%_g-4T}HQnh)Grxfci>kOKaIGT7Kv!%*)myKbLLX_WM2OFo z`2G|Um(C!3`2vEJg|xEaw2g4EY@SJ0!?)riE{uXSsUT z8$#$|8S1{=gQkPKPgcmc4_{kbi<2i$;@fY(eZ*(ZoIy*AwAqtX zQ&WTQzWdJPu|t)0xm?yjKE*Z#0s&mOZ~>=JpMJ!rPMyNFYu6BoXfXeh)V}f^KYsjC zJ1TSg_HFY_Pq*<*GA0W(f6aZ=ubPjBl6=%p$V2Uf5vVC1jhb;|P+v3>j-nB0o|K2` zSw-;g-3-^<8E7sV2ItsZG>pqZ<;20Lm^2jSlX6itA&Yqj!^P{y3AuPMaU_AUn+nT= z1i_OOYo?9{5j%Yb)#FB^c32-Y4eNrMp*>JFE)RiEcLMe06ey>~Ew*qukoM4*l|L)? ziW><|uK^1m*m`C?c7lMbs6^G;MW`+r0VkiUX+i<+6i-C${yj+EzJjVXD^XE0293ph z#)-q(?;-5>5O^jGg`4?Z6Z2VSBq}G3z`c?@+*wdc3+XC_-wEfw^(ZgskGf$W;`Zb* z2;QW;5j@g10+7yX%1jihz1Ht^-?siUW~?-3(&Y?AsSXKKohSWE9S$o zauI5`Y(T8)9?ME|w@waEQ5yg;gL%jN6%8YD|1M_$nr#F}TfjUGB#SNc&fZkj!U42! zpiq31eCrC*cdy~ZrZwpI=ii~rJAXjOPH&St;+;Qt#FE8J5Q#opKt<7L6m#ax!7H!4 zf_ClNp?&-Ic=_d*(WOfl+`W6ZHJ3$taT_;oH2FGo=wQky|66apg|lbRKFVXWG>J_P zhXe1w|2|%P@kLWktakeL?MskXw&r?F$z&2+wrs)AfBtim@1>VsGNJB2{`g~)E^6Dx z(_{oq$*BIN&{m26jPxb|17H_?X(p$9_?m*ld!fUb5^0 z+%qP_H>ellS)CBgd<(%rZ^N7S0o-#Zpk~=@)URBIhLuYgE+W9mYZjuB>{zuBP6^(s zd8k^y2#)jL(1Nm7S&aZ|_VzmA-MtMBBm1-Ooe>(`5so46qi$viH7zGz3Tf@OZK$8O zfD^(j_=-m%oZAJ`+B6Bs7)L1p>atGd^tT3 z9@q>11+$Q@dSF1y*}>AXGG#eANt=XDe2IHQKZGN*H{4l$(Zn&WE6hQC;V?Ah^=H4j zqGfPbII?=;0YM(UbD7T(ZIuBTo&u1ytW99h)DvKm zG|_zLzeCe^M^Jb2C~8k1LG76%s5$i&su`A_If~^|$Kf{}eu`IL`5D^3)*c;R>3|OH zU%|o!d?AgEPjFc0=vwLCy?f}>r;ia(fk7u2%^ zuws=Ju%(q$r|SM80Ex^57fm2|>T5KO%0g^VcLJjq8m1I+@}ar*#U8lw1|Xc#jRM{s z(P?9l+_)T}yc|TbyCXc9fEzIYk( z2%0H;j;#0LW?$VI-SJ?=AUM8Z{qm(q#>Ata6F&VlwP*o?LwX>U(+R=sx6wF01JQ2| zP=nBVpuDAB44ayOYFa+q)-Z2h#Mqxy|F@C;pcDMV`yqZ{4^Z)tvs^V&K5D#}pC;@X zG*IJ)3I0UphX_wEM*NF?h#db4;cpKka^f?Dzc~!g1)7C5w-G(GiT&=0IQyL7WaJw& z2+94MfMZ`ENUa_i`W|9A?;@Pp1I^PWAkF@8l&lHvhXK_3OE9Ae7p-`JL>U3p1~5h& zmC>BjNd#(|C^b&-^7rtQLsxmtJX>c?Mt}&%b8$c3l0pr}cb9nIJfzevZFA&7zaqQW%$F!|- zzyJO3jRq1ZY>o2TYp)pq=H=yK*sx)bxM$CvrVSftVgX2XWMySx$dDnpbctH|Z;)1x z5DdeAa64SNy(u`HsX0r!mdvJ5-G*o9MmPueLX5L=h?*ukuNa}#^AH%;p8$Fn!JKYr zEXqZw>;%Wl$9L$0mjG%R+8?nGDG-C+L-V*Hh+aO)nOOc0+jKU;wPPdP!#_l9;2)95 z_#Ki12%@q1NbcH$#D$B9(dUZNe~Qp|37bVA`X(n2A+hEocnSt`=I@SJc2~qRy1-ME z&-~{I8Z944=Hf_I+=64?bTsGoL4sN$nb8&Qp&!7zWjWAT#eNdWadn0oLW>1858zuc z6G2WM@r;g0fA}_113Du(JrBv7tUKyw#Ua+tGSLtsUmrlr@cu~l?~V9}eW;21z{mOn z!+XOw{C#-x`k*Q=6E~@0Bj-;bxOD|wg9%P*_b|uOJ-q;_Ta;zYd~%(0D8qX$`! zd+~gNRld4;m}k;oEFw@*v2SrC>T40ZdChE$ntdOtTC^VD(Skwz)@7X9x*m&07hu8I zLhN0%02Qad!|)G!;nf%a3mw}1lpvv|Y4^YJhhMym9&i2@J^%0qdcE}~-hcZ~=+&h& zx{?K)uARFu?2JyGI^o@S-!-AMjSV3AC8I}=HbN?4ef8B>&Gqo%!wncpN=opX-~0x@ z{`Id-_}kz97O%hl`Xd0@AX2&C{qA>0xW#Y2`6hPm+-Wq#!i5Xbv13Pc?%WyOx^+YM z?%mC`G>PgIXaz#GYiqP${Nfjn`fTS_DDK*|s|kDe?v1NgsiFS{X=N-;XV$%WAOX$rJ?$6gOYU+zZZIB7f9%l6_~esBIpo_=d{ zErq<*(SAtn@ZC}P*DpiM_&oRq_dz`SeI#gZ2C0dfr%puj{tXHdHBf|tUU!ervjUEx z1CeB&M0OWy)t+$9oQ%}nGCK4GGQq4>+2&&h;QeYZLIjp~)L{0hC&!=*@L^|$JrOM( zh0xyh@P4@;EvJqm?y3hoPIxvk|6pnp0yCP^4>3&`+1-%NdY4+}UAXi5!MA<^T80J?bzA%bXeQ2~DbU;iI|{=$D@Ty`d|A3cihe|n4Hp?O9P z)1DgU*RQt6g3@AKKJq259R3nzM~>mf@soIPtqkS&?i&EeJiB-AF15#PYK2?o{^7$1 z1~?*_Nq_$HpUvzpLAF7(b?a7RQq7+~ADNk%Msta!6{ImF=r(|qzekTAkF<bnr%#}Trdc5OJtVWP_Yga4z+Xvxo{!1g3yy3$AK%67ZMMRTiu{4msQ zU&m)4;38hQ2()_oZH*(c;2?NH6lh0wCp3(w@AlnS1SQQ#38b$Dj$Ip2L9Nj=yayVG zbVn0SQYST=OJ*s35l?n6c<9S{2v|q%Kvc}8Hn~gJq2eAKvpEI?LX?w8YIG)0kVy^F zmCr)|iDqll)B>QKt_C%7s;Uf)GYS#Scn=u(Hhj69q&{8-xV?y-y8zedp)`*>b5iIG z*RXyFe8#b--$Y$!_4S7UWHOjHY~5+8Gxp#fHIOzztqoBD$t+hBK)x&IF|%MOUU}(% z(**k|CX5`8;|D&$o4@%bXJ-QF75XaeUcg(wdJV_-ZHM>4EqJKW{5NkRQc;bhFMt>Y zH^NycL7O=i3nP*UF)l)_9-+@52b5i=@33&uVhXKgw%M9M=G>>Be#&w&BcKA3*zfn_ zz<~os3n`ziEu=*b9y|!2&j*jkV?y~@mS9`_G55~8(o;o-l$!%$c1U#3K!`c`406_DR};rkaz!N?=eI#QSrm9oh$8Y9#m@5qNM7 zl^;z))8O9Ja`ay$;6pPI$?uP-W^>jTr&$(cn!w_w>F7~ka#&YJC&U@LhtfwFLvYNR z1mDihh<$$+=_YE0Ftv)$kIFr}aJy(M>c)>n?W9p~5UlR`6A}6LkhO$t#FEe5T#uHO z^WmjG5*pkMzB%LJ+rN$G=MH!e?}G2}UIg}RKzPzH`f;78g?qrca2B=lJ;ct^d>=D} zfawfBL6n>}9MOUS1V|T-pUm3#(6XF)Y2wSOO446yoRq_Qx=^ceOoq`M{)9eb(2LL) zhu|BM!O5fxV&rCmDRTBS%caaBw!LI;7E9G{-SA%<4b&DuB$;uIb%@*~(vA5h09lM1 zSKz*M4n>>|UViz%@N)Z~Vak|M*s^p9e*5~X)IKzGI#64@{8My)^9_8tWi6IX9*5Zl z!!d8{Xv~{53G-&o!t6P7Fmvu~hO;o|quH3l>shmBV(HSwMk9&p>+8|?gT8pVon^j> z1qx}SDO08xA>XlM2lDgtF=E6BmR*W@^X5IFfdn9}z-eW!xVYHlEh;K9%jdT6-@0`R zn>KAStW`CwpiP@L4S)Edf1oN*~kIi0CBy23wn0PXlJnjO7qrqHaQZQeX?IO1EEb9T?9 zhM}29;d9b-@g3L-wA3PS_JN8u!*oLs^W$`QZw0I@4q5Ig*-@mB(uzk~1gMFi*q#2admtSU#%?CEgu zIh^co?9*-32=t8tnh5F$wg#Z~COnI#!NoCg(T{R%q}FJvg!i-Es2fR*NRzE)G@o_( zL~4-_2&S&|`MS_&WZ!qt3^QLy$KXHy1*%5&qlPC)I7#?N4n*Pv$0XDQ&$bn4)@tV9 zE}T@l!7+vAF3n7xn9)QhZ0LZs1tfvTK$t|HP~m#JmGne%UD*WkE# z7Q+Vg!Hezw54FvUm{T$lv&I$SwRSI3$SCZuyo^@~pxj>Fv19%m^!W8_`19-S@n>qN zH-GyZ{O*l6@Ed9g8x)4yTf#mnzW~h**6c15>Q}$|)f48JtyLB;UThW+WVXra7fUmY z9Xr;f+j#{x`65e}EHNPX$xnV_79ecrUc$X@-8usd`A%w2nnq=9lTp`VX*I>!`4q~W zYs-ogt355hTbhT1O6NKa-fM%8+ArmFAnvF{!dZz_!$SnmeTAyIrKm3*kNOz}aFq^0 zpm-R(Q%1oxbqw5789!|-8kfyPm@{X^?1^YBEkx7wLNv@Pp}BXEv+PAQuULed!a?wk zA>a!7pozle+c*p9YbTL@cpa(R=aJNg*5HHC^e9;udXpS|_Ekg6O0yJ@4 zs%93!|Je?t9^6Fg;T<>+?n33var6}n;h0fGjW`3bZ@)ym{5i-d|dndAP%fvhJ!mc;qycL z@a0#Zs~4)OIMb2j1D&VCyk^ZBtY5z#Q>RYF z8w9vrR-h9g6$+diHf%7gyw75RQR!Mdc(jqq0oTFDGy+JtAHaL|FkGK*gk%2_H1C;* zx?S@Ty80zj^|uJ7`$#q2LhQl;G;NxP_}L>!S22!4nW(vg;H5JNU7;^pPa$o*L(_?- zcEwFJ9{U2dpYDQ7&i2mv2ydQ&=;nE7*}4=>+bCRH=AwS%T-0t^jH-PbQ1i`~@ZZ0~ z*}etwkP8t<0}}N$NLSvce{lnN$ajA86rJx&NY$~8#s}tQq#l58;p>}a8n&ywEaE?RGM-x%Lb1gy-ZX;gT$hzwgYp5p3ZX$Gu6Tqw@3iW2* zm+^TYQpoA#ANw5P@>>YgvsF++sA5cTy~`f}kdn<}WGcpoYeMwS z4MemTbd3&K*$vJR-=cq)j`V?kf;V1!1#^oh;e)Q7(Lqbp1XMd?!o7eMvu46Y^C(bN zfmFatVdCsdx_+$;-8*%`YcF=d&)dI-R|urnU;70%ZP-lfQP@_VYi4E4)+RO}1QrRn z767#4uN5`rk)I>s)nb9||JWKs;F&ymvWXLb1`HTre5R)<7z|?e?Aebrkln6WW}o(d zehgWr8)qxcSo+2)PzA@SZE$XxhRE9Sh^;9=aOFriHcUYH?s1mzlR3j_|K#eosQh>( z66F-~xO^uq^@iY~=^3l6;d_d5ijy<0vt=Q~n<@~myiH);L89RX1>q*rI=B-~Y76&)jY!-&Nua4sA6Xwo zN}Ezp=)Wf2O^7_8e9*t~Et^Dhsu#TZy-;7AkKlJ-(?p_)XM9>Mp9he9cm>WyrKl^+ zhX2rJYGe9rtSeew4d=PD90L2jFs`-&jpx+1#)UD?8Z^_KbLRAgC#N@BXks>!?-bEQ zz3?6T6JyV0aU>02jY7*V&VqGUI6M(+@B<$BwGq8* z15%BgdClhp9KV=jX7f?=xE%;Ryonb22@UI)z%geMyu~Bo9h(LBMDj-?>CCT0 z>gq9SJ4^bzC~#1L%mvxR z$nN7qL>jB9V(-9l=`40EnuB$7XJE&&C0O~<9Q={~&8q}ZhYkb~o&Mib=uV&HtYA*q zat31OW6>DauUU^@z4lAI@*>TnmpQw?)B)W)cg6ST>0_xqnLF%p(o!F9U~ zO{b5dV$XV1eXN%tT`)JGphiO zLmZ3Bt4KCei!`&p^>mo8oq~JqECYyO2~C&cLGVq=hHKIwH1payAq%deY&gd=9LKaV z1E_iW!%L?=dEy{_5NgdZL7w*Vd1#UaTj-RZhI?)?{DpnsE$9N*LTcfv+Z-MCG2%hv z*%R>5?2;^+*Ut&N`s8sq?_T3`@Oi0eBga2QV__!zvkDQR59vAf8GLuHA|010$}ymv znT2PLN4%i{{_oDfv4^JUSJb?I_Cd9)ZU@_2y%aY`eMsMkpor@e2(?QPRXsrCtYSn4 zbptY}eQ3hPX~MOP9f-&!z7JBXc(yg+{yHgdYkm^p#h12r*)qKI`#<3AH-3lF!}2hG z%oxtnmf&g6=EWCZ#)uL5@OXTtF>!)+{IbQ%@LIc9jn zIw3!mW}0;Z!3`(1QafEbj+RyQu|671Z8rg-T`S<phqv`YA@bBJ$(7tu>>|cYH-D`Qj0zR5@Ejw1jvwbzZ+g2m6VF7~E zMj%K4`4>(^^1|0hJ)lsRUq`a~5~3An5IKLCT51LyqX)sC-xDo`-Ql8X1!seK4>3;@ zs?Huk)Kx19GjR#G2ld~cK%_<{EHzM^<4>@=@_HjYw5K^6c&m6cn$8|$pK1D2%hASR zX$~S$61{mHl{4uBjiJUnLI6cW=6tCp=X7-?8s<&Ko$)jUIa!z$QfhShYOyP4;g~pr zpwaojcag~Gi0Gisa81rfTpPIhQ5VU77l3TCwL&Nu!m!*SX!o-h@jAgWXW9(p4I7H~ zt=gx(S&nW`EisE`l9Z-JAh9A-K0~+h)u&fkI{EpNMpjRKWY=AOC3DXxonJl;+Zg zskD_yt7wXAA*E6K*xlxAmOu zt`N`^cD?%~g&-cNLfCN^$*2G%^Nk!2!hin(+;=JPd>5Kc^*KT;>_&iE266fh2?~kd zNnhGSVCm11Rlv1%F=uT08*}p!J^C@t7y1g3S^}EFD~CN{Z5A54UH~%tIRWOO=8HIu z=>@i-Q``tLE+E$N9;Ru(=HV6imrX{n@B>7q4uyB&I5-v+qiM+$RIi?jignXbxnwG8 zrWc`UN)bGhsP)F@!n1P~;FFJ-Lde^Ih8y1#1JqjT11Z|lLjQ*X%ZbZu1Nd6t-mn-g zgS#P`(HY*XKB!+Z6R9SRwGI@^^pk;R0VsCkGAfGm@nCc&B4@th1L`YilIDoAGSruh zMcs^XNZc=D93#cCF#Jb9NAsv``aj)~%zV$BP}km(Yxa1gYwxi*e^e3Q!H)uvO%M1I zyLIV`b}zk*Km6|Z*tC8F`hVDu!egzLwQEOUy#7m?Nn0pz)?kPn%}!(v$Ta4gS$QLX zdwWU}ZM)&e# zbi_ua#N${Qkjph)_5*;~DdU0CV5Dhd?!jUk-Jv zGz1#%qw3T_q_nD*&hYr|A}%or}o6g$P_c2=|R|k!WFlorES} zbQ;2#Ks5XO*Dt_*_AuP%55aT(AiQV4ARmM4`;&;dsySH)`CcQ$U6=qSV9U$koHqfH z`~gUe8HjjM27F^P@Ni-dT%W9BdxsIC7L1w?>CPfaN4$CNWCXsT@6kfDk^V_tdm z($}RlVdeA1Lq0^C3GyJp>?c6(-KU9I0)KWl#Asf%3?IPf+h?BB{C##K+IkW`3+ss7 zynu%#BTz$MD{)IJaMqD3siDZ}Z&6t|6wVcM=_gd1vIck|FT8uVqh;6tq|AwJ0w}wa z*{pT1oCCP(Oim-M|0sZD{%97L&}lzKD_>d_vjjSjuQlrh3ID4Ep+YN z4IN&x77xU4{q9YiJ8e1IrdMrbPP4vz9SNtc83Yc2Mf*QmG!P&pv=Z{qKKslpZ>wLn zPzyBLFOol^d@{LIUaN1~2hxdZ#j76Wx7h}*^2;RCf`jP9i4z7`%CB_0Up9CY|1)Z4 z?K{~Y`dM;LP4VC&&7L_(ters3Q-~A+6kS~e_s+RU*4^aHD+)2G7=4oCRk>L3;I36 z0!#9FXi9oEtb{M8F9Foe04SE(39i9C5!kVo@5XK3hk2*}2!LertX#R$2$lp@0w@4! zR=0#t0P28_9pA;RTX$MZndWfp$TxWN_iqwFmI){B+4X(gzoTz1NSZj9RV>oEHl4V( zgr3Ijc!cd(do&2S;W_ddeUkA=e3Xgkj6sM_&xLPVHtJSRM)>9x=3%}t z>(;(oj5Gd&n{cgLjPT?F#3p7VIyD2ysRMu#0&o0K`caGM^gpBqVqUGRs$cOaXY;S& zDH(?3=)Q=I>OudeCr!ACNZdF>fgxzj7*IH4L7J*(&@yc_qQl-tpm2cMtZX`Y3h96V zqa|i)5RHS(Df)FuYP`w~OHorW1m2yFe z2t&6{e{vpck}wd^BGNAYIYew=0o-Ra(EWaF^6+ggSsM3 z6HbS1n}_s9=!?CqmKv8;n0Li?el&pOMC%l@giAuEl`jd7G*VjtWn^U1Iky}{o3?G; zj$gd`3$yxW`#^cQ!_nN(x`1Hy$*@SihmPRbfRM22TAQNUM3vv7d-+7tK3bX*=MAp#%Ilha&gp)5=#z7eIx-!)4Tug1SheFQyR)L5( zE77bIA=;Rf#t;V_a30--hg;?#bms!!t7dQJrw`M7_!IaS6(Kcq5K_|yBRG8+8t09G z@0;y>kuL3ra?)oV(hSZ@jxB%9hF$ev<$5%?M7&B7k}!GP*aM^n=3R(P@uZdn-n0sa;bIchR(V7TkHgkQ~w-o{?E- z*|G`gW@=PEOHzId&8rym8-HG9BR)K)6vD(t&#TQ?E@hG1@uaNe# zp4IA)+S1}gTP>yBhWX3PrhKqe& zehw8o79nuuxFy^sB@9>PHTo{p91*SVsdC19n^5`1cGMl&&g*8%KO`WOdN*Dc=|lW!{OC8ObzsHm``0XKqp}RpKU?& zxD13x^n$No06g<%A$^?=yuK)AXHrpW0AHAjimYO$Fty$F^KeWUi9`58AxCln8QG{9U_KXs^j~yhQbb^BY;NT?cDsgM>RNS3eip1?( zkH?H=apK|`xW*1gJcH(2W>;zyHMI{bi^Gu}|+l`2NC0 z6pYMAJKn$YicTxb^yz@5OP6!p)QCl1j}K!;jWyawzK?CftzShm#p;V;bjT!kbj8OSmG=IAjiDrF%&X+DlO9T7b`56Abr9Wx4%Javq~a`W+67yrS@XZ+$DG+p@K z{8?$^1_`9i)d((Kg7Bbzh|{$4j4MF$`||`GwU6rexKK~?y?WhhYgyd9))d0mF5vbY zj_)-Jeo~XPC1m=GP)%PQg8SR=IO%Xg;J6!0!Q(|}-)=aE4MfuTKV7JSIw6`xA86h< zBy~PeCqnd^^laoG1t6I)a;RkrX{Ohni-b=bl`p?6A=fHbdkW#}*u9(fBFV!}oj!98 zTQ+};&Ye0N07>(-|5-cy@wb1#(JyJYi>zm}*vMQO%a<-gd)C|j(du41qmiU-^r^H2 zSuE2{t7-CgbT7fSwS!ji1UP|S_ws495MYy@Nh@?VaBS_P{Q4xp{-YowJ*(OmXlwv! zEV8q*(a>m_s|Nh$IkXl;G1H6DMrZvUv>aHBz}j(0tsjNt`aDF|jzVz9TyyAAzKq$6 z3Aqq@aFzKftdSPR(_9NRBmVFb8jkHYU!0odYArMC_zrD$@4c(^Aqe!a2T3~VDW8^} zY0CJ^5&DK^*#fpRI}fqXHUW({Ih)nfC!pD^jn=xGW|P%Fbp+BA1|d!DlP>9pD9yO& z#*css_N|2)%R?V6$THgT*Rpo73F*ok2=CYc-^5Yyjva!y{JYtp6 zrx7}J5YpdTk z@-c+YeU6r|wUQLaQ<_I&K^SG#BTUb>_Oxr z^PN5b=izN|eZ3RG?+ze#`V)i?tTfBmvAG28)+LA>++;o(2p`;q=w~|-*s}uexnmI@ zKNuKKUuhBnG?5yJrdxdeIK&UEN8s}<2p-&u5KXYqq0I;%+JeA=4REiW15fb?gbT9} z9!*dzn}!JEy`OG@cmFo{_EYHhZAR0AQaB275h(0~U|ttQsoi29FF@evZg`I#K=AN> zgjlATTB%`J9|UGlQ+=`q{;zkzb94^^hqoZIx)d$>`nazLqD$D$=Q|Mjau1?k?1YEy zHV*p`-l^1>2R2dD)Au|03A`JYqhZE4c(*QvYuCqcZrcJk*}v^$1h#L3cRMGSotxm> zu^!IV3uvYdM{r0tq;lRvBBvYT+1(Hs{2p9Gdce1vfRB0jHZ`HP3MuJF0Z6m4KqRMH z{(uf+N&uw+uy3_?~$CUUZKkdu{*b!*n++}ZOOIU=9;gHbqYG%j7dgd<-cF-LB+ zSfEhmmsZ}cUB70|!3lVS1`RU8u8;IY0)>1RohVScSmkuDl|_5$TBK){Kcpi(T5(fe zozYYNUAuR4Y-BePF6_I}Lj3i}giC}Fx_KP#two5h;Y`1J7y(3^ngEKgFGOJdIJh=U zfP3|L_|}Yre{GQo&Hd^L@UIw+(29ISR}?ZF2hWO$Xjwi1p5@H5cr;oTjfQ7Q5!?$$ z!n1%pKOgRo^5I`ti131ZBt9CB)XX7>&ZL<&a~OS{p=M*%KYIwgvj-zonnjZ>gT4 zg60W>;nJ!d*+IXkrGWM3^+PhRH`2p6yVHd87JO(N^OliW@aJW~o7WfNq1_Or@J1=H z{tCurF8kU(#;?5`#p@7hG!&)(%XEK) zHZGCEf5xwC1(B*%DAz>(lbrhiRj!ttgMpyYO0h`Xu;0sgvQ9T7V(ddWVnD6D`ea)y zpbG@5N2`ZorMET9)IU>yF!-pvt_2vI^c?o&p*%`gUG}Hps>A%@K04Oyx?zp6c^>_W z1>n7M1dfg45Lr12sg)z>1CiGeOl$KAr~<^64@YQ84x+1uAhw1~kR_NewSxJU=kj_8 zlFRduTsjiT#pH#&UPK@+9E#Ke=G8g3kA^ZFhBP@fhk%)tjf8k+CKA&r=;CPuk)Hk` zQq$>AOz(?GXz|@)as%zR^7qAJq$~f?h~6OcoF@BRQ+*(IFr4K9DEwj>HJg@WZrnaIPmB@P6m{dBC79H>|LDrcdc!vVs5vhzn zGyWaKv))0BW%R{tjQP_UoseeUM5aDN=ly_=z(B_F8Uyt=5#BSObtlNlflTZF4)eT& z)Ijne=FuNC$#{?8{4;7N4np+u3Cd=K@R4QlSpNSZ0R2;>w#5QWD|iH$r@1XipCG$@ z+vKP3+Y;;gt7-pIQbXoT6st+Q|9Ti{pnK<0zkN2GI`_7E6hbuR!W%{*vaS$O-bbim zLIg`-^$7S^Fj zSol8tqk6zQieY|t1V(fr69gl=B18~{hj&GQrk%_?T}OuXKxAlF1c$y0AA#i^+!6j9 z{W-7B)DrJed%Q>O!L;m7)H*g*u4;Sdl#T~_X5=HoR8Wa^9edDtlqf*)w>p;e&<3oFs||Axv1Yd2X$L!qkhXA z)Nh_mA88iqHcdzMrczXGo`x!hHN3CgIMZ$x0u|v=L;5BbkT!RgQdfhE@JP>$*jLIEQBOCu@;z&?$z9SrB?s|NLJ7kP&2i znl?gh$Me?{{5a3QivPU;BC%=Cj-g>)GoMHK$VzKr*iz5(wTP1wt{SVp<_g3eWLFirrZr9Z$j!Va z#~oyaO?8G7O^heUn`;njVwpCaXe2iOxeH<2BcEXO`KGE|!CRNbcj zR&J~{pK`~VDiCWdN4$<)BW6FVSx#J4g;*`?t7TkWC1Uym`?U;fERI(zz5-Ewbz9GS zvi`UDSRGj*S?LxlP0aRGPrX?83>zMjACT`q=6c4NH05XAse|WXGSyPnUUunf#w13qWd6n;6@tJX@G#aO4xt|(>GGqSvd%)CR>7uChkl(Rak zB(rd&e5M~{<+JnKak^I#Mp?R@(XDJETlsOEO}ewtT>zgO8nz! zU8(kGWHeFw^<>)9Iqe*Fyq>Y`4E+}cTIsJuKUtZm&Aqu){k*d3f86&r*&bcDjr(z= gQqOuL&m!Re2S#{Uz{Hm4`2YX_07*qoM6N<$f;-uY-T(jq literal 0 HcmV?d00001 diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/initTableMixins.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/initTableMixins.js new file mode 100644 index 0000000..1470857 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/initTableMixins.js @@ -0,0 +1,166 @@ +const initTableMixins = { + data() { + return { + festival: ['元旦', '春节', '清明节', '劳动节', '端午节', '中秋节', '国庆节', '其它'], + submitLoading: false, + searchMore: false, + tableSize: '', + tableKey: '', + formData: {}, + formRules: {}, + formLoading: false, + tableLoading: false, + tableData: [], + tableColumns: [], + pageForm: { + searchName: "", + searchKeyword: "", + pageNumber: 1, + pageSize: 10, + totalCount: 0, + pageOrderName: "", + pageOrderBy: "" + }, + guavaIndex: 'index', + unionGroups: [], + threeUnits: [] + } + }, + filters: { + date(value) { + return value ? moment(value).format('YYYY-MM-DD') : '' + } + }, + methods: { + dropdownCommand({action, value}) { + if (action) action(value) + }, + + fileHandleRemove(file, fileList) { + return fileList; + }, + fileHandleChange(file, fileList, {type, size}) { + const removeFile = () => { + fileList.splice(fileList.findIndex(v => v === file)) + } + + if (!file.size) { + this.notifyWarning('您选择的是空文件!') + removeFile() + } + + if (type && type.length && !type.includes(file.name.split('.').pop().toLowerCase())) { + this.notifyWarning(`文件只能是 ${type.map(v => v.toUpperCase()).join('/')} 格式!`) + removeFile() + } + + if (size && !file.size < size) { + this.notifyWarning(`文件大小不能超过 ${size / 1024 / 1024}MB!`) + removeFile() + } + + return fileList; + }, + + columnChange(val) { + this.tableLoading = true + this.tableColumns = val + this.tableLoading = false + }, + tableSizeChange(size) { + this.tableSize = size + }, + indexMethod(index) { + return index + (this.pageForm.pageNumber - 1) * this.pageForm.pageSize + 1 + }, + doSearch() { + this.tableKey = new Date().getTime() + this.pageForm.pageNumber = 1 + this.pageData() + }, + pageOrder(column) { + this.pageForm.pageOrderName = column.prop; + this.pageForm.pageOrderBy = column.order; + this.pageData(); + }, + pageNumberChange(val) { + this.pageForm.pageNumber = val; + this.pageData(); + }, + pageSizeChange(val) { + this.pageForm.pageSize = val; + this.pageData(); + }, + pageData(url) { + const address = url ? url : loc() + "/pageData" + sublime.showLoadingbar(); + this.tableLoading = true + $.post(address, this.pageForm, (data) => { + sublime.closeLoadingbar(); + this.tableLoading = false + if (data.code == 0) { + this.tableData = data.data.list; + this.pageForm.totalCount = data.data.totalCount; + } else { + this.$message.error(data.msg); + } + }, "json"); + }, + notifySuccess(msg) { + this.$notify({ + title: '成功', + message: msg, + type: 'success' + }); + }, + notifyWarning(msg) { + this.$notify({ + title: '警告', + message: msg, + type: 'warning' + }); + }, + notifyError(msg) { + this.$notify.error({ + title: '错误', + message: msg + }); + }, + async getThreeUnits() { + this.$set(this.pageForm, 'threeUnitId', null) + this.threeUnits = [] + this.threeUnits = await threeUnitsByUnionGroupOrUnitId(this.pageForm.unitId, this.pageForm.unionGroupId) + }, + launchFullscreen() { + const element = document.documentElement + if (element.requestFullscreen) { + element.requestFullscreen(); + } else if (element.mozRequestFullScreen) { + element.mozRequestFullScreen(); + } else if (element.webkitRequestFullscreen) { + element.webkitRequestFullscreen(); + } else if (element.msRequestFullscreen) { + element.msRequestFullscreen(); + } + this.calcSignTableHeight() + }, + exitFullscreen() { + if (document.exitFullscreen) { + document.exitFullscreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitExitFullscreen) { + document.webkitExitFullscreen(); + } + }, + toggleFullScreen() { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } + } + } + } +} diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/main.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/main.css new file mode 100644 index 0000000..88ef59d --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/main.css @@ -0,0 +1,119 @@ +html { + display: block; + font-size: 16px; + min-height: 100vh; + background-color: #f6f7f9; +} + +body { + min-width: 320px; + max-width: 640px; + margin: 0 auto; + padding: 0; + font-family: "微软雅黑", Helvetica, STHeiTi, sans-serif; + color: #000000; + -webkit-text-size-adjust: 100% !important; +} + +#app { + min-height: 100vh; + background-color: #f9f9f9; + display: block; +} + +[v-cloak] { + display: none; +} + +a, img { + -webkit-touch-callout: none; + text-decoration: none; + color: #000000; +} + +.text-center { + text-align: center; +} + +.text-right { + text-align: right; +} + +.text-left { + text-align: left; +} + +.m5 { + margin: 5px; +} + +.m10 { + margin: 10px; +} + +.mb5 { + margin-bottom: 5px; +} + +.mb10 { + margin-bottom: 10px; +} + +.mt5 { + margin-top: 5px; +} + +.mt10 { + margin-top: 10px; +} + +.ml5 { + margin-left: 5px; +} + +.ml15 { + margin-left: 15px; +} + + +.ml10 { + margin-left: 10px; +} + +.mr5 { + margin-right: 5px; +} + +.mr10 { + margin-right: 10px; +} + +.mt20 { + margin-top: 20px; +} + +.p10 { + padding: 10px; +} + +.mb20 { + margin-bottom: 20px; +} + +.flex-box { + display: flex; +} + +.font-bold { + font-weight: bold; +} + +.text-overflow { + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; +} + + + + diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/theme.css b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/theme.css new file mode 100644 index 0000000..3c89dda --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobile/theme.css @@ -0,0 +1,177 @@ +.van-pagination__item--active { + background-color: #1867b0; + color: #FFFFFF !important; +} + +.van-pagination__item:active { + background-color: #1867b0 !important; +} + +.van-pagination__item { + color: #1867b0; +} + +.van-dropdown-menu__bar { + border-top: 1px solid #f8f8f8; + border-bottom: 1px solid #f8f8f8; + box-shadow: none; + overflow-x: auto; + +} + +/*.van-dropdown-menu__bar > .van-dropdown-menu__item:not(:last-child) {*/ +/* border-right: 1px solid #f0f0f0;*/ +/*}*/ + +.van-dropdown-menu__title--active, .van-dropdown-item__option--active, .van-dropdown-item__option--active .van-dropdown-item__icon { + color: #1867b0; +} + +.van-tabs { + z-index: 1; +} + +.van-tabs__line { + background-color: #1867b0; +} + +.font-theme-color { + color: #1867b0; +} + +.van-nav-bar { + /*background-color: #1867b0;*/ + background-color: #FFFFFF; + z-index: 11; +} + +.van-nav-bar .van-nav-bar__left > .van-icon-arrow-left { + /*color: #FFFFFF;*/ + color: #000; +} + +.van-nav-bar .van-nav-bar__title { + /*color: #FFFFFF;*/ + color: #000; +} + + +.van-dropdown-menu__title { + font-size: 14px; +} + +.layui-table th, .layui-table td { + text-align: center !important; +} + +.layui-table-fixed { + z-index: 9 !important; +} + +.search-fixed { + position: fixed; + top: 46px; + left: 0; + width: 100%; + z-index: 1; + box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%); +} + +.van-empty { + background-color: #FFFFFF; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + width: 100%; + height: 100%; + z-index: 0; +} + +.van-dropdown-item__content { + border-bottom-right-radius: 15px; + border-bottom-left-radius: 15px; +} + +.van-dropdown-menu__bar { +} + +.van-dropdown-menu__item { + flex: unset; + flex-shrink: 0; +} + +.van-dropdown-menu__title { + padding: 0 25px; +} + +.list-card { + margin-bottom: 20px; +} + +.list-card .van-cell { + padding: 8px 16px; +} + +.list-card .van-cell__title { + flex: 1; + color: #969799; + /*font-weight: 500;*/ +} + +.list-card .van-cell__title:after { + content: ':'; + margin-left: 2px; +} + + +.list-card .van-cell__value { + text-align: left; + flex: 2.5; + color: #323233; + /*font-weight: 500;*/ +} + +.van-cell-group__title { + padding: 5px 0 5px 16px; +} + +.van-calendar__confirm { + height: 45px; +} + +.van-index-bar__sidebar { + top: -webkit-calc(20% + 20px); + top: calc(20% + 20px); + height: -webkit-calc(80% - 100px); + height: calc(80% - 100px); + -webkit-transform: unset; + -ms-transform: unset; + transform: unset; +} + +.van-index-bar__index { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + font-weight: 500; + font-size: 14px; +} + +.van-sidebar-item { + margin: 0 !important; + padding: 10px 12px !important; +} + +.van-sidebar-item--select::before { + background-color: #373AA3; + left: 5px; +} + +.van-sidebar-item--select { + text-indent: 5px; +} + + + diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobileMixins.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobileMixins.js new file mode 100644 index 0000000..74c416e --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/mobileMixins.js @@ -0,0 +1,98 @@ +const mobileMixins = { + data() { + return { + tableData: [], + mLoading: false, + finished: false, + loading: false, + refreshing: false, + formData: {}, + pageForm: { + pageNumber: 1, + pageSize: 5, + totalCount: 0 + }, + themeColor: '#373AA3', + pageDataUrl: null, + yearList: [] + } + }, + filters: { + date(value) { + return value ? moment(value).format('YYYY-MM-DD') : '' + } + }, + methods: { + async pageData() { + this.mLoading = true + if (this.pageDataUrl == null) { + this.pageDataUrl = loc() + '/pageData' + } + $.post(this.pageDataUrl, this.pageForm, (res) => { + const {code, data} = res + if (this.refreshing) { + this.tableData = []; + this.refreshing = false; + } + this.loading = false; + + if (code === 0) { + this.tableData = this.tableData.concat(data.list) + this.pageForm.totalCount = data.totalCount + + if (this.tableData.length === 0) { + this.finished = true; + } else { + this.none_data = false + if (this.tableData.length >= this.pageForm.totalCount) { + this.finished = true; + this.pageForm.pageNumber++ + } + } + } + }) + this.mLoading = false + }, + async onRefresh() { + this.tableData = [] + this.refreshing = true; + this.finished = false; + this.pageForm.pageNumber = 0 + this.loading = true; + await this.pageData(); + }, + GetQueryString(name) { + const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + const r = window.location.search.substr(1).match(reg); + if (r != null) return unescape(r[2]); + return ""; + }, + createYearList() { + for (let i = new Date().getFullYear() - 50; i <= new Date().getFullYear(); i++) { + this.yearList.unshift({value: i, text: i + '年'},) + } + }, + startLoading() { + this.vLoading = vant.Toast.loading({ + message: '加载中...', + forbidClick: true, + duration: 0 + }) + }, + closeLoading() { + setTimeout(() => { + this.vLoading.close() + }, 500) + }, + doSearch() { + this.tableKey = new Date().getTime() + this.pageForm.pageNumber = 1 + this.pageForm.totalCount = 0 + this.tableData = [] + this.pageData() + } + }, + created() { + this.createYearList() + } +} diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/svg/top.svg b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/svg/top.svg new file mode 100644 index 0000000..8ff62a1 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/svg/top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelAgencyImport.xlsx b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelAgencyImport.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c3bf1521a44ce7bb65dec041a1e999a9281c9684 GIT binary patch literal 9172 zcmaJ{1ymf%(gqfHcXxLuxCB@rIKd&f!{PygyF)^74elO-O9BLUhv06(E&PzYdvn9P z|Lb#RXUf;x#Oy?N31fR|r+SOXfiYb85#*|Wu-W{$cWdUKp%!01;zW+C-K`ljdLAYyfJ)zt+E$A(L$649(-1h1D&!fY;vrwli zcUQ;zXUxpYjMv+x?>n~?cL8kM0Hr$weLuYM)6metLf+&>!>W^y0Jz=uhLie($E1L21ge8 zc^{si>EYy~#70=hHq?N}Y$%mj6;`gJZ+qb#z5>Th-uAD22o@ zaTo@mXK$zDY11)+@8y5DteK^+H&8NnDQL%l%A}8H%gnU(T8^oNgFi3sh@QT{U_i$ zZ~8?T9soys0372Fz?~hP>}(z(&yDSq?G(Wby6`(hH5E<*GRw=x#Q^~;9e%aiaJ?Up zj7>ZGKWKHiy2_TWbVM?vY;LaJ49TdMdpbqQZHtCsqT&F8L)BgUr}MvAXm`T$&T?j3 zNzuK8SCI2pbMc6`ew&)e4j7A)giZ7FXB$H&TOh`@tFfBuuzg+VX0%suE`5GCTqRq_ zVb(z!<`6QgNzl7|8VJBy{BHguY|q%EZmeY07})XQPM=aK^Q6*FGnQzmX}_` zLK_f|y9wv*u{unOf%NLeaGJQxk8#EN|VC!c6GnV|j0P-&ZS38iEqq&KR)6=-K;9<9F^w10TLu|tR zFWH|eY(E`DeZY2=8?^;zO8~YjJHPBl+$BwI^K@5lnJ;t2bZa_ZXkDmccEX2}HKx~l z7^k!OmKixDGQhfQ!L97rprw8u4npKww-eQnZ*6Zks&wKgBV^jX%55~wGxbifT$Gzp z4hJRhVO1FezxQ*xS6^S{OHxeaEOMAaxY3@)?L`)r8xd z+y=#TZr%;*gZM(qza_9zYEM^{nGykm7 zY0f8+@5&;X+M1robe%1%8iHypBxz2IK(nMU%edBF;7CcbSaMKFvhmFK)f|<3ijJK! zM6GySMv_62A)i(tWE~Xo2hW-|B-P5ZeXvQ20Yu>nZR)PLdELzL76IfY zKhhoC!6ofFk10+PwU}zA(!hpyD=6tHcX1yqc$>*ff5claa5Q;pZoG74S@ky;ks^arofnsb2JLDZnn7Se`6pa{M#T zS9~squ9)Y$MlLxevE|i4&m4xV9i)-~oBd?kAi_JPy!aeCZ)J{B?1n~UZ&^jLVj3cS9WqBozE3eJ-X%%mz$2k^j&>p5 zrABgW8pRWZj4^+T{_==xK;dl_LYxYxkd3giSNOVljh(8!vAa(crx2l4O2EABFX( zj@S1r`N7{c-&l#pPp~XmS-iP9EcbqMcQMp@*G;~oj-w<@ed?m`YoY6V4^R_`GKQQZ ze?N_+wVvO4&sqiY6_)nz8*Dx}?rgV@SV3L2V92!)wnw?F^~kT$P`-FxeNFQJd--GD z@ZjZ6<|Z~KPx1yiqJ-f&C@?TmykCL#Z?T`kKV5fUQ{Ik%2elbz%lqYCbFA?$1v@!R zozM!k3%Z1C7-6BV<$E;O22whKPguQ`BEH!cBS7E9*R-?H(mr~l`m5ZMDG*l(L?8_Y zCy?4kC1aA~FiH>!J?Q6#{meN}pLA45v!O2qsl>kcdIP${7Tw3t@dTI=G18>*mx)<%P^nv)Wv?TQTZbSqMR`6sS*}w+Z2=ne> zJTVvc4wT$OB}&R?TbF8gn;I_Vs>2F~66?^~owk|x@Qod$skYmE?wrgtrBeiF8+zON zfC8QFGwnOmR?X`%Figmb(bVwm>dK|XLoWCd@UO!Bo)=op`^kYkw|3LhkaTT0>l?!-5@O(T zU=-XMl}Kvp;5UJos^XfumSJ$f^*k-$FyIRen4(A+rHmlo&=Dk*Vymu1Zz9HFj6|jC zSSC?K#O9SE>15D&L^>>QuW@&4I@vTDu)JLV_VW5O$KhFcetvX%hS2r;>GA5=bK%Vv z#!kRnsl4Ul!`922xfji?>0TE*y&ASntjDeQr!#h~Z?>U3gtXXSU!9E!rwe;s4QzV< zIO+mlS~a)scuv{g(HQ!oNr2I}cDrr5|2VNV=`*cVSCt6crOU^IzG;ZXREnLBeIo(4 z3ts6E1UH-WwiW(}D>?M;ex8*s2x2y=3p`ioZ$Zg@AxGv3QU|?P{ap*9Thm;wIJxSU zH`RzW@gH?ujI2kR>ovxKFztvSC(zDl8f%wnr&+93!~EX6d^qL& z``pxeE~dY1ai_tXmC4OR`uB3=yAi%K~y;8(&r16SmsC9`vN(Se^xP8-!Y~M>gu?i)GRI}Fl8o&=v{ZK zRf_726y4Y|wQ`TAU$Cl+Z8>I!rJds;Gn6xppLU5cXM$FXIlaU8+aS%-I9GpJL&V6; za1pLrS_x)pqW&#lt-YaWm1oBQLdxDo3^SPig?kas%tWteO41^xTrot^k#bIfk4fHK z*zTA0!in`1?Ak)dsZ zPi4m!i;7Wh5L3x?YxJ>h2?M*=D24HjaX{d>P!LC7qADq1rPPsblTm0{MlfOVybW<*_$q zi7f6q1FsMO1j1m)TkVbWc<;z@V3B6;VE#BY7||q+g#5M<;h{6UWB{ zZbHW zzxGrVOgd-|j)LcCuBc8^4XgVQT5w9(ym+bE!lp)*D$J(U%)|GvW&(pox!lJ4j6qw; zbA^uwnTSR`6HeH&IM~6{sa84kQ}AG06t_P`cd*^HC~t)kFA@sU zH$7nPY+|3uo3{em;e(TZ7D>GtMe~OkyT!eBNqIGCtF%m*ym{r8ES;;3cMKESUkSD@ zVF+$#ro1^3S9rL4NIbjiZRsqjls?xNzo-WW{J2=B0JRk-U4>2YpHMZ#^o7jUpsDVf zI)4>*5jDS?t-VsfAKM?o4Icq&Wn3j(CtckU8qsrpn$x~(GZURGMm2FV@nCrUyurq! zO&CeCfWS?(pi6`zguP{D4iG%g#(y&rZiaHC8|;D$eiLFaATq^zv6TjxLJ@PS6m!yv z%iH;U765Z&Gf`!EWWlY-fw1t}%fvJvexbzNgj0Qbz7J#>vO>2EC5bj)q%~>6UngRS zfLX^p(Rqi6LYG{tGiXuX=^2)5LdNM>*w-uFUW;w1xi$WNFF6IA(z)Cs>xJRLM7YZf zFbr`G%0xeIW)jDlVs*mAYWULKfdz##w-P%sAu)aymmmgi$S|33_`IkKLXqBbrktUZt($fq04nRZrR&G%NbG7ARMe zfb-D2)%n;Lr0~z`gG+d~j?R?C)n4ID^iK@rStK)+j#$>p<>W2178a!Yb;!pv~{I(<;3$X)-GshQn&%VgVxY4c){ zRi3T6q*2Jm!m?fGQ@WQpk;T3C zy0*3-uESm8#bzz`Gz0T<1L!9gqZ&TcfJLXr**3%-VF~&Tnr2`%By}{+D{<{p75;d4 zITR_xaNJs%YCNrzkUSw3PXN?Fm%pvZX;Xgdg3ruT)-%A_&p?+HR^~_7uLD(yp2&As z4#$yh+)?8q4C_%bpELXp8^iSN+UR-0=BZI)ci=%g*);*ob8~f^E(ca0|8y%7$d>(f zL#kNmALKGGsr|6B>hMWcu!z2ggsCI#!RbIP$U3jRZ96w`1i||(hc56@g~XR{u0}-( z(e`ef#m4t+QqaVVJy#$vkN)Np0S*@j$lpYUX~ReVRue>4Bch{;xC*8A0k2yGg+C%s z$p+uKS(J5XS8pXaBG23;=-FI9ftUihJ}jSaD%l#P-bA+^>-esnSF&Fl+hjcNB`N%SYd+ z4B)$^c`7xAc{#16z04%BqA@do5SVMHKow|BpKfPvCW5XUi#$$;tdYGf$^*e>$^$UL zD>9z@yu40ZHdumVY6AM=Rp=0)Rg6nbL$_H&&au4#5g@b;v^7Fbl6M*N^k^m0n^A}i zkR#Rihn|9FLR_*HxjV)`N^s-5MfZOSBy^^Orzz2Y3#$;7fV$Zw^)Y!$3SnN$@@v4% z@QQD#H2@XTi>P9K+6S4=XxReZ2!N>K826TU4TqK20UP86PaMFCu$;h$eZW|I1h$2a z*L*sjVh8$ zBP#3T`*GPaJA|>6s`LHPLHm!NP+h1Jgy)YsM(}az5C=?FC~<6caSQv5DS2pjc3DBY z>qHHj=>ax7R>Kam0xL(UjQb&-7YCzJywBoti5z$-tae#f#vk8Emw9#-9)%wo)1_+% zPO;R$mJ?pEe8NZRm)#iNVqJ}WH7bK%X{dI`3cKKHAT?+Mp16RSdCOZ9ZOh+X zQSqWqA(IFK7pu*8E`{_!PFhK2IK17)`Sf&q?byR|r=d#NNpN~Y-ri?{a10{eTaZ}r zZu_EGSk4$#HwkfZlAkF@qczW(Hitzh|>J>5L(_ zb=~}rYCcpBOL7udNm;seuQ@T~+^14aX2*sulmQ*q2jtg=4cgawb_-QRxUpx$;`pq( zV*GCoJvLF&qrKClAcet=l}B+~ZaW=CTyN`9&>fEfeAEH@BZ-ph)x9(CH&KT4-drvk zOBG8K(Uq)v|5(30y;IGVCSuhVOOuNbAjGZ6-xAQ5tSh5addx0025ymr#J7$18KIxZI9)k_YQlK3$L1!o9le54$Zo|l;kb9r-o=8HKjC-9Pk z+zg4XBx(CS7X@fC#ziz#z(UJ^k@_RWzChAJg{ef{WUlC-Q!p1rRc(}izo~%YY&W+x zMfXkA*evnogyZ%3aJXHbew~`jt<7yRSXbKOS)GSKhy#YrJEGP=Jub3N?tX^Fux|sX zm&J(U^`$M1^<$i_7mQvxY6})NxLo-yhLf%?JUdcmX0B80#jk5mFnY|krn<|Bt-kcL z#30Sv;!21LFYa{^Fp9Pwx}?o4k#aDYerGTq?wRQEZxq{M3Y|E?*2(yNh5eTBlu9uJ$bku35$mkgQK}2$i!I131new_A|S5jurh+G1nEg zx?ZIbHI`BrHeCb-b+!_TGd?*fj2SBodt8dn28sboc3%u5H=zqxP~I$0_Y6J?6BAwM z$I?aX1@?;p5>2diRKBj7O6W-r%}i3Aig0RX3j;e>GaC%r0Q`^Us@4&l_7Si>yTuIj zWU8^%iRPJd7S0G_%Cr=HqC6`VJ9MtG`H`H(UbqEfMM(X!Q{HmYWj%<-t9W!uXP z=?^!2lsh*>k!V&l8II?_R z?Q4DQGK#($ZGlNe03_3jPg(+gx+G-})92{aog2qmW~8|Cyv!O~{Z* z06WWyRME7DX}e$sr1kJd8b6Boo2kU5PbELPk`1c{R(^2G9d2EFOVVcKdH*c${$_&q zVKUI^9-v-$xKMsqWMA3YS^X@;#>&6wWJL@*l)eq_ah)vNMU}InArsm2qi+Ag$9aIy zq%X_P|3grrm@O(bbxMJF&Mu)iUVRV2D`rxaHEpeJm{VQ4y4>LAho>V9ql7J_#-st% z60U)ozCM%3E=tBEF)p}VL1y>}Qxzj8ktH$pWLB1}Rr5ydhb6Oi_cd~-5T)Xho|8E_ zM+*Z=##?XPIvW%J=sG@2PKN+D)n}uZS@Fyw&DOac3m?%|2b)3ijv1J&pT#}V*|Q4_ zq(;x(Wcq!tay)otB`0n)^+eR~nH!ENN9zPay*{qR8#i-yoRcVbmHA~e!iz;V;Jm$I zjw}7#)Q`b((}^2FI*FQum*)xGkn26hoZ^H{yAvC2FaPXBnwr6-!$mNpjLV#`o{FDO zyqQtx4fg++)1V(v)d!haKdps(@VYeJKfGIdAT1F7mSKLBER7qI?P5j!a`-@2Y_!O` zVxi4Av5@b{8+-XA%H0oBW5j9hw=|0?F^+$NiB7uONLlhUZX{SB)nm(xYVvbd@)NP^ zacNOH@^pK-;3r+uJOOZ5weNsz-1+|MCcuB=+1puW%2-`b$EyBCUxs5kc3fX4qStix&`?Vg(Wk@=BO?l94SJ&g5mJ6 zj$~Rh0XSX*pmTsT&NL*}tEHYYu%inHKyRzEoh3--X`xIK*+jmM-yGtvg02!adOgjlC`xBB~$ku7efSt)SR2XtG3x?wNg56*xo1cW}Z1Ij5!OLBR1mXio1I6q z0CO|&n{tvC5;x(qc2!0>`gDy`k5x)PQT1oG*mWhzp{NlFLFs^>tt6Uz`k9bk@+FeTCm2{IpK1F;NNMu z$B^@@J(Byu1iu5&pGKdCphulwMvMQ}`ROwM%h;n&{%ViL9@{?-9sFtU>9K=H;a~P> z{;Bq#LkLeHdP=MR)((8w(tjKMi)4SQ{*)yCt$zLxGJdQ7O&R~MNk1~7zuM!Zl_CGb zi#|^G-wl{KS6qAA&(lomcRw8u-0Q#PRZn|(TH^cN zgVh7m``E+Z1;76V)}M3dh5f1e7rpf74tYv2{kEw8Pqp84)6*e8&1Zgh!1nM}co_0O zVf$Z$ex$O0wZ|29{I$Y=5Zix_{3*5lsQYWxGX6{VH_@#Kg!<{MXb%TPU>@Y^Ngnn7 E530kuX8-^I literal 0 HcmV?d00001 diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelEnrollImport.xlsx b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/templates/TravelEnrollImport.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..665e5869c9ef604dd556c09800806c2cfcab1295 GIT binary patch literal 8813 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 Om{16Ja*Cw)pZ*6}6BDWc literal 0 HcmV?d00001 diff --git a/src/main/resources/static/assets/staffbenefit/therapyRecuperation/v.js b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/v.js new file mode 100644 index 0000000..071b5e5 --- /dev/null +++ b/src/main/resources/static/assets/staffbenefit/therapyRecuperation/v.js @@ -0,0 +1,426 @@ +/** + * 根据enum获取选项 + * @returns {Promise<*>} + */ +const getEnumOptions = async (enumName) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/enumOptions", {enumName}) + return data +} + +/** + * 根据code获取字典选项 + * @returns {Promise<*>} + */ +const getDictOptions = async (code) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/dictOptions", {code}) + return data +} + +/** + * 根据code获取字典选项信息 + * @returns {Promise<*>} + */ +const getDictState = async (code) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/dictState", {code}) + return data +} + +/** + * 获取校区 + * @returns {Promise<*>} + */ +const getCampus = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getCampus") + return data +} + + +/** + * 获取代表团 + * @returns {Promise<*>} + */ +const getDbt = async (jdhId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getDbt", {jdhId}) + return data +} + +//查询当前用户管理的院级工会 +const getUnion = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getUnion") + return data +} + +//查询当前用户管理的院级工会下的单位 +const getUnit = async (unionid) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getUnit", {unionid: unionid}) + return data +} + +/** + * 获取代表小组 + * @returns {Promise<*>} + */ +const getGroup = async (jdhId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getGroup", {jdhId}) + return data +} + +//获取所有开启的教代会 +const getOpenJdh = async () => { + const {data} = await $.get("/platform/jdh/Common/getOpenJdhxx") + return data +} + +/** + * 获取院级工会 + * @returns {Promise<*>} + */ +const getUnions = async (delegationId = null, isPermission = false) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/unions", {delegationId, isPermission}) + return data +} + +/** + * 获取活动院级工会 + * @returns {Promise<*>} + */ +const getActivityUnions = async () => { + const {data} = await $.get("/platform/activity/basic/union/getActivityUnions",) + return data +} + +/** + * 获取单位 + * @returns {Promise<*>} + */ +const getUnits = async (unionId = null) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/units", {unionId}) + return data +} + +const getClubUnits = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getClubUnits", {}) + return data +} + +/** + * 获取单位 + * @returns {Promise<*>} + */ +const getActivityUnits = async (unionId) => { + const {data} = await $.get("/platform/activity/basic/union/getActivityUnits", {unionId}) + return data +} + + +/** + * 获取本分工会的单位 + * @returns {Promise<*>} + */ +const getUnionUnits = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/unionUnits") + return data +} + +/** + * 获取福利单位 + * @returns {Promise<*>} + */ +const getWelfareUnits = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/welfareUnits") + return data +} + +/** + * 获取福利单位的二级单位 + * @returns {Promise<*>} + */ +const getUnitsByWelfareUnit = async (welfareUnitId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/unitsByWelfareUnit", {welfareUnitId}) + return data +} + +/** + * 获取协会 + * @returns {Promise<*>} + */ +const getClubs = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/clubs", {}) + return data +} + +/** + * 获取届次 + * @returns {Promise<*>} + */ +const getJc = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getJcByDict") + return data +} + +/** + * 获取当前人所管理的协会 + * @returns {Promise<*>} + */ +const getClubsByRole = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getClubsByRole", {}) + return data +} +/** + * 获取当前人所在的协会 + * @returns {Promise<*>} + */ +const getClubsByUser = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getClubsByUser", {}) + return data +} + +/** + * 获取文件类型 + * @returns {Promise<*>} + */ +const getFileType = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getFileTypeByDict") + return data +} + +/** + * 获取基层干部的角色 + * @returns {Promise<*>} + */ +const getJcgbJs = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getJcgbJsByDict") + return data +} + +/** + * 获取审批员的角色 + * @returns {Promise<*>} + */ +const getSpyJs = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getSpyJsByDict") + return data +} + +/** + * 获取协会类型 + * @returns {Promise<*>} + */ +const getClubType = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getClubTypeByDict") + return data +} + +/** + * 获取系统名称 + * @returns {Promise<*>} + */ +const getSystemName = async () => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getSystemNameByDict") + return data +} + +/** + * 获取工代会 + * @returns {Promise<*>} + */ +const getGdh = async (open = true) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getGdh", {open}) + return data +} + +/** + * 获取工代会代表团 + * @returns {Promise<*>} + */ +const getGdhDbt = async (jdhId) => { + const {data} = await $.get("/platform/gdh/common/getDbt", {jdhId}) + return data +} + +/** + * 根据id查用户 + * @returns {Promise<*>} + */ +const queryUserByIds = async (ids) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/queryUserByIds", {ids: JSON.stringify(ids)}) + return data +} + +/** + * 根据id查用户 + * @returns {Promise<*>} + */ +const queryUserById = async (id) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/queryUserById", {id: id}) + return data +} + +/** + * 查询用户 + * @param query + * @param unionId + * @param unitId + * @param sex + * @param member + * @returns {Promise<*>} + */ +const searchUser = async (query, unionId = null, unitId = null, sex = null, member = null) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/searchUser", { + query, + unionId, + unitId, + sex, + member + }) + return data.list +} + +/** + * 获取代表可以操作的教代会 + * @returns {Promise<*>} + */ +const getJdhByDb = async () => { + const {data} = await $.get("/platform/proposal/common/getJdhByDb") + return data +} + +/** + * 获取代表可以操作的开启的教代会 + * @returns {Promise<*>} + */ +const getOpenJdhByDb = async () => { + const {data} = await $.get("/platform/proposal/common/getOpenMeeting") + return data +} + +/** + * 获取教代会工作资料类型 + * @returns {Promise<*>} + */ +const getGzzllx = async () => { + const {data} = await $.get("/platform/jdh/Common/getGzzllx") + return data +} + +/** + * 获取疗休养活动 + * @returns {Promise<*>} + */ +const getLxyHd = async () => { + const {data} = await $.get("/platform/zgfw/lxy/common/getHdList") + return data +} +const getlxyHdCd = async () => { + const {data} = await $.get("/platform/zgfw/lxy/common/getlxyHdCd") + return data +} + +const getNowLxyHd = async () => { + const {data} = await $.get("/platform/zgfw/lxy/common/getNowHdList") + return data +} + +/** + * 获取基层工会 + * @returns {Promise<*>} + */ +const getUnionList = async (unionId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/unionList", {unionId}) + return data +} +const threeUnitsByUnionGroupOrUnitId = async (unitId, groupId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/threeUnitsByUnionGroupOrUnitId", { + unitId, + groupId + }) + return data +} + +const unionGroupsByUnionId = async (unionId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/unionGroupsByUnionId", {unionId}) + return data +} + +/** + * 获取活动人员范围 + * @returns {Promise<*>} + */ +const getActivityGroup = async () => { + const {data} = await $.get('/platform/activity/basic/scope/getActivityUserScopeGroup') + return data +} +/** + * 查看该人员是否在活动范围中 + * @returns {Promise<*>} + */ +const getScopeUser = async (activityGroupId) => { + const {data} = await $.get('/platform/activity/basic/scope/getScopeUser', {activityGroupId}) + return data +} + +/** + * 根据code查询活动项目下面的类型 + * @param id + * @returns {Promise<*>} + */ +const getActivityTwoLevelType = async (code) => { + const {data} = await $.get("/platform/activity/basic/basic/settings/getActivityTwoLevelType", {code}) + return data +} + +//获取二级教代会(双代会)工作资料类型 +const getJdh2Gzzllx = async () => { + const {data} = await $.get("/platform/jdh/Common/getJdh2Gzzllx") + return data +} + +const getLocationVariable = (variable) => { + var query = window.location.search.substring(1); + var vars = query.split("&"); + for (let i = 0; i < vars.length; i++) { + var pair = vars[i].split("="); + if (pair[0] == variable) { + return pair[1]; + } + } + return ''; +} + +const getConfigKey = async (key) => { + const {data} = await $.get('/platform/staffTherapyRecuperation/common/getValue', {key}) + return data +} + +/** + * 根据多个工会获取单位 + * @returns {Promise<*>} + */ +const getUnitByUnions = async (unionId = null) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getUnitsByUnions", {unionId}) + return data +} + +/** + * 多个单位或小组获取三级单位 + * @param unitId + * @param groupId + * @returns {Promise<*>} + */ +const getThreeUnitsByUnionGroupsOrUnitIds = async (unitId, groupId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getThreeUnitsByUnionGroupsOrUnitIds", { + unitId, + groupId + }) + return data +} + +/** + * 多个工会获取工会小组 + * @param unionId + * @returns {Promise<*>} + */ +const getUnionGroupsByUnions = async (unionId) => { + const {data} = await $.get("/platform/staffTherapyRecuperation/common/getUnionGroupsByUnions", {unionId}) + return data +} diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/BaseManageInfo.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/BaseManageInfo.vue new file mode 100644 index 0000000..40c7cae --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/BaseManageInfo.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/BorderTable.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/BorderTable.vue new file mode 100644 index 0000000..ea639c8 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/BorderTable.vue @@ -0,0 +1,82 @@ +/** +*Desc: +*Create by: jug +*Create time:2023/11/10/11:07 +*/ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/DrawerUserScope.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/DrawerUserScope.vue new file mode 100644 index 0000000..c0ec177 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/DrawerUserScope.vue @@ -0,0 +1,10 @@ + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/Enrollinfo.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/Enrollinfo.vue new file mode 100644 index 0000000..2bc334f --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/Enrollinfo.vue @@ -0,0 +1,191 @@ + + + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/FileUpload.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/FileUpload.vue new file mode 100644 index 0000000..c240cdc --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/FileUpload.vue @@ -0,0 +1,42 @@ + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/Guava.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/Guava.vue new file mode 100644 index 0000000..1abfa00 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/Guava.vue @@ -0,0 +1,146 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/ImageUpload.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/ImageUpload.vue new file mode 100644 index 0000000..56c36dd --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/ImageUpload.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/LineInfo.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/LineInfo.vue new file mode 100644 index 0000000..203622f --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/LineInfo.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/XghEnrollInfo.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/XghEnrollInfo.vue new file mode 100644 index 0000000..270a616 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/XghEnrollInfo.vue @@ -0,0 +1,158 @@ + + + + diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MCard.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MCard.vue new file mode 100644 index 0000000..074cb62 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MCard.vue @@ -0,0 +1,50 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MLoading.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MLoading.vue new file mode 100644 index 0000000..43fa4c3 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MLoading.vue @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MTableLoading.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MTableLoading.vue new file mode 100644 index 0000000..934cc76 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/MTableLoading.vue @@ -0,0 +1,140 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/VantFileUpload.vue b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/VantFileUpload.vue new file mode 100644 index 0000000..71afb61 --- /dev/null +++ b/src/main/resources/static/components/staffbenefit/therapyRecuperation/mobile/VantFileUpload.vue @@ -0,0 +1,671 @@ + + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_cxry.xlsx b/src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_cxry.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..aedfa00872288285e89727ca66ccec3e194c8e2e GIT binary patch literal 11284 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_sbb.xlsx b/src/main/resources/templates/staffbenefit/therapyRecuperation/lxy_sbb.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9942a68fb70d224ec1f6caf852af76d9d96b0bdd GIT binary patch literal 11312 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 literal 0 HcmV?d00001 diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html new file mode 100644 index 0000000..9de5c57 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyAudit.html @@ -0,0 +1,978 @@ + + + +

+ + + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html new file mode 100644 index 0000000..62c2e23 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyTravelAudit.html @@ -0,0 +1,806 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 返 回 + 调 整 + 拒 绝 + 通 过 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确 定 + + +
+ + + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html new file mode 100644 index 0000000..b5891ea --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/audit/TheRapyXghAudit.html @@ -0,0 +1,974 @@ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 返 回 + 调 整 + 拒 绝 + 通 过 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确 定 + + + +
+ + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html new file mode 100644 index 0000000..dab55de --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/baseManage/baseManagement.html @@ -0,0 +1,698 @@ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 下载模板 + + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件 +
+
+
+
+
+
+ + + 取 消 + 确定 + +
+ +
+
+ + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html new file mode 100644 index 0000000..0eae8ce --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/line.html @@ -0,0 +1,1048 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 下载模板 + + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件 +
+
+
+
+
+
+ + + 取 消 + 确定 + +
+ + + + + + 下载模板 + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件 +
+
+
+
+
+
+ + + 取 消 + 确 定 + +
+ +
+
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html new file mode 100644 index 0000000..d56b4f2 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/basicManage/travelAgency.html @@ -0,0 +1,473 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 是 + 否 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取消 + 提交 + + + + + + + + + + + 下载模板 + + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件 +
+
+
+
+
+
+ + + 取 消 + 确定 + +
+ +
+
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/index.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/index.html new file mode 100644 index 0000000..b33d3d0 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/index.html @@ -0,0 +1,5 @@ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/mobile.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/mobile.html new file mode 100644 index 0000000..e085b7b --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/mobile.html @@ -0,0 +1,23 @@ + + +????? + + + + + + + + + + + + + + + + + + + +${layoutContent} diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/platform.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/platform.html new file mode 100644 index 0000000..18cbc56 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/layouts/platform.html @@ -0,0 +1,42 @@ + + +????? + + + + + + + + + + + + + + + + + + + + + + + + + + +${layoutContent} diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyQuery.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyQuery.html new file mode 100644 index 0000000..1a4a7b1 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyQuery.html @@ -0,0 +1,1771 @@ + + + + + +
+ + + + + + + + + + + + + + + + 关闭 + + + + + + 选择标段/参加时间(设置前请先勾选需要设置的用户) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确定 + + + + + + + + + 下载模板 + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件,时间格式请书写为2008-10-1 +
+
+
+
+
+
+ + + 取 消 + 确定 + +
+ + +

+ 家属信息 +

+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确 定 + + +
+ + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyUserQuery.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyUserQuery.html new file mode 100644 index 0000000..caf3e07 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/TheRapyUserQuery.html @@ -0,0 +1,1493 @@ + + + + + +
+ + + + + + + + 选择标段/参加时间(设置前请先勾选需要设置的用户) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确定 + + + + + + + + 下载模板 + + + + + + + + 选择文件 + +
+ 只能上传 xls/xlsx 文件,时间格式请书写为2008-10-1 +
+
+
+
+
+
+ + + 取 消 + 确定 + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+ + + + +
+
+ + + + + + +
+ + 取 消 + 确 定 + +
+ + + + + + + + + + + + + + + + + 添加家属 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 取 消 + 确 定 + + +
+
+ + + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html new file mode 100644 index 0000000..143f7cd --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/joinUserImport.html @@ -0,0 +1,276 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + +
+
+

+ 线路 +

+
+
+ + {{item.label}} + + +
+
+
+ +
+
+

+ 旅行社 +

+
+
+ + {{item.label}} + + +
+
+
+
+ +
+
+ + + 下载模板 + + + +
将文件拖到此处,或点击上传
+
+ +
+
+ + + +
+

excel表格:{{excelRows.length}}行

+

合法数据:{{tableData.length}}行

+
+ + + + + + +
+
+ + + + + + +
+ +
+ 上一步 + + {{nextBtnTxt}} + +
+ +
+
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html new file mode 100644 index 0000000..6017dc6 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineAdjustment.html @@ -0,0 +1,451 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html new file mode 100644 index 0000000..74438fb --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineCluster.html @@ -0,0 +1,516 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + {{item.clusterName}} + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ +
+ + + {{item.clusterName}} + + +
+ + + 取消 + 确定 + + +
+ +
+ + + + + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html new file mode 100644 index 0000000..687b7ca --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineSelectionOverview.html @@ -0,0 +1,687 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

{{editTimeSlotsForm.lineName}}

+
+
+

+ 时间段{{$index + 1}} +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ 新增出行时间 +
+
+ + 取消 + 提交 + +
+ +
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html new file mode 100644 index 0000000..dfaf3ca --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/lineUnionSelect.html @@ -0,0 +1,892 @@ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

{{formData.lineName}}

+ +
+
+

+ 时间段{{$index+1}} +

+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ 新增出行时间 + +
+
+ + 取消 + 提交 + +
+ + +
+
+

+ 时间段{{$index+1}} +

+
+ + + + + {{row.signUpStartTime}} + + + {{row.signUpEndTime}} + + + + {{row.changeEndTime}} + + + + {{row.playStartTime}} + + + + {{row.playEndTime}} + + + + {{row.travelAgencyName}} + + + + {{row.contact}} + + + + {{row.contactPhone}} + + + + {{row.principal}} + + + + {{row.principalContact}} + + + + + + {{row.trafficTools}} + + + + {{row.estimatedCost}} + + + + {{row.estimatedFamilyNumbers}} + + + + {{row.maxPeopleNumber}} + + + + + + + + + {{signUpModeName(row.signUpMode)}} + + + + + +
+
+ +
+
+ + + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html new file mode 100644 index 0000000..736f452 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/process/queryStatics.html @@ -0,0 +1,231 @@ + + + + + +
+ + + +
+ + + + + + \ No newline at end of file diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html new file mode 100644 index 0000000..53806e4 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/lineStatistics.html @@ -0,0 +1,804 @@ + + +
+ + + + + + + + + +
+
+

出行时间段

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + 取消 + 提交 + +
+
+
+ + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html new file mode 100644 index 0000000..b872c29 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/travelAgencyMonthlyStatistics.html @@ -0,0 +1,278 @@ + + + +
+ + + +
+ + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html new file mode 100644 index 0000000..1ba1801 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/statistics/unionLineNumberStatistics.html @@ -0,0 +1,93 @@ + +
+ + + +
+ + + diff --git a/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html new file mode 100644 index 0000000..1bb3b78 --- /dev/null +++ b/src/main/resources/views/platform/zhgh/staffbenefit/therapyRecuperation/theRapyConfig/TheRapyConfig.html @@ -0,0 +1,573 @@ + + + + +
+ + +
+

疗休养配置

+
+ + + + + + + + +
+
+ + + +
+
+ 设置 +
+
+
+ + + + + + 至 + + + + + + + + + 至 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 需要 + 不需要 + + + + + + 需要 + 不需要 + + + + + + 需要 + 不需要 + + + + + + + + + + + + + + 需要 + 不需要 + + + + + + 数量 + 详细信息 + + + +
+ + + 增加一条 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + 重 置 + 提 交 + + +
+
+ + + + + 取 消 + 确 定 + + +
+ + +
+ + + + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html new file mode 100644 index 0000000..cc9fbc1 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/baseManagement.html @@ -0,0 +1,651 @@ + + + +
+ + + + + + + +
+
+
+ + {{baseData.lotName}} + + {{baseData.baseName}} +
+
+
+ 区  域: + {{baseData.regionalNature}} +
+
+ 创建模式: + {{baseData.createMode === 1 ? '校工会' : '分工会'}} +
+
+ 报名时间: + {{moment(baseData.signUpStartTime).format('YYYY-MM-DD HH:mm') + ' ~ ' + + moment(baseData.signUpEndTime).format('YYYY-MM-DD HH:mm')}} +
+
+ 活动时间: + {{moment(baseData.activityStartTime).format('YYYY-MM-DD HH:mm') + ' ~ ' + + moment(baseData.activityEndTime).format('YYYY-MM-DD HH:mm')}} +
+
+
+ +
+
+ + +
+
+ + + + + + + + + + +
+ + + + +
+
+
+ 基础信息 +
+
+ + + + + + +
+
+ + +
+
+
+ 床位信息 +
+
+ + + + + + +
+
+ + +
+
+
+ 随行人信息 +
+ 删除随行人 + 添加随行人 +
+
+
+ + + + + + + + + + + + + +
+ 提醒:如果跟报名人员同一房间,无须选择! +
+ + + + + +
+
+
+
+ + 如有随行人出行,请添加随行人 + +
+
+ +
+ 提交报名 +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/index.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/index.html new file mode 100644 index 0000000..e2348fd --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/index.html @@ -0,0 +1,165 @@ + + + +
+ + + + + + + + + + + + + + + + +
+ + + +
{{item.label}}
+
+
+
+ + +
+ +
+
+
+ +
+ + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html new file mode 100644 index 0000000..4a00293 --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineInfo.html @@ -0,0 +1,896 @@ + + + +
+ + + + + + + + + + +
+ + + + +
+
+
+ 基础信息 +
+
+ + + + + + +
+
+ + +
+
+
+ 床位信息 +
+
+ + + + + + +
+
+ + +
+
+
+ 随行人信息 +
+ 删除随行人 + + 添加随行人 + +
+
+ + +
+ +
+ 提交报名 +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + +
+ + + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html new file mode 100644 index 0000000..f546afe --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/lineList.html @@ -0,0 +1,911 @@ + + + +
+ + + + + + + + 您的入校时间为{{schoolTime}},疗休养额度为1500。 + + + +
+ + +
+ +
+
{{item.label}} +
+
+
+ + + +
+ + + + + + + + +
+ + + +
+
+ +
+
+
+ + +
+
+
+ {{o.lineName}} + + {{isGrouped(o) ? '已成团' : '未成团'}} + +
+
+ + + +
+ 预计费用: + {{o.estimatedCost}}元 +
+ +
+ 出行时段: + {{moment(o.playStartTime).format('MM-DD') + ' 至 ' + moment(o.playEndTime).format('MM-DD')}} +
+ +
+ + 组织机构: + {{o.signUpMode === 2 ? '校工会' : o.usUnionName}} +
+ +
+ 成团人数: + + {{getGroupCount(o)}} + /{{getMinimumGroupCount(o)}}人 +
+ + +
+
+ +
+
+ {{o.travelAgencyName}} +
+
+ +
+ 联 系 人:{{o.contact}} +
+
+ 联系电话:{{o.contactMobileNumber}} +
+ +
+ 已报人数:{{o.signUpUserNum + o.signUpUserFamilyNum + '(家属' + + o.signUpUserFamilyNum + '人)'}} +
+ +
+ 已报人数:{{o.signUpUserNum + o.familyNumber + '(家属' + + o.familyNumber + '人)'}} +
+ +
+
+ +
+
+ {{o.baseName}} +
+ {{o.regionalNature}} + {{o.lotName}} +
+
+
+
+ 联 系 人:{{o.baseContactPerson}} +
+
+ 联系方式:{{o.baseContactNumber}} +
+
+ 旅 行 社:{{o.travelAgencyName}} +
+
+
+ +
+
+ + + + + 查看人员 + + + 我要报名 + + + +
+
+
+ + +
+ 取消 + 选择分工会 + 确定 +
+ +
+
+ {{item.text}} +
+
+
+ + + + + +
+ + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html new file mode 100644 index 0000000..ad993de --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/myRecuperation.html @@ -0,0 +1,586 @@ + + + +
+ + + + + + + + + + +
+ + + +
{{item.label}} +
+
+
+ + +
+ + +
+
+ + + +
+
+ {{o.lineName}} + +
+
+ + + +
+ 线路类型:{{o.regionalNature}} +
+ +
+ 出行时段:{{o.lotName}} +
+
+ 随行家属:{{o.companionUserNames ? o.companionUserNames : '无'}} + 随行家属:{{o.familyNumber}}人 +
+
+ 审核状态:{{o.stateName}} +
+
+
+ +
+
+ {{o.travelAgencyName}} +
+
+ +
+ 联系人:{{o.contact}} +
+
+ 联系电话:{{o.contactMobileNumber}} +
+ +
+ 已报人数:{{o.signUpUserNum + o.signUpUserFamilyNum + '(家属' + + o.signUpUserFamilyNum + '人)'}} +
+ +
+ 已报人数:{{o.signUpUserNum + o.totalFamilyNumber + '(家属' + + o.totalFamilyNumber + '人)'}} +
+ +
+
+ +
+
+ {{o.baseName}} +
+ {{o.regionalNature}} + {{o.lotName}} +
+
+
+
+ 联 系 人:{{o.baseContactPerson}} +
+
+ 联系方式:{{o.baseContactNumber}} +
+
+ 旅 行 社:{{o.travelAgencyName}} +
+
+
+ +
+ +
+ + 修 改 + + + + 取 消 + + 满意度反馈 +
+ +
+
+ + + +
+ + + + + + + + + + + +
+ + +
+ +
+ + + diff --git a/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html new file mode 100644 index 0000000..738ca2f --- /dev/null +++ b/src/main/resources/views/platform/zhghh5/staffbenefit/therapyRecuperation/userSignInfo.html @@ -0,0 +1,84 @@ + + + +
+ + + + + + + + +
+ + +