liukangdong
2024-05-10 c58ada7f49aac20b06ea2ebda2cb5c006decf122
Merge branch 'master' of http://139.186.142.91:10010/r/productDev/dmvisit
已添加29个文件
已删除2个文件
已修改69个文件
已重命名1个文件
28998 ■■■■ 文件已修改
admin/package-lock.json 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/bookings.js 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/devices.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/home.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/notice.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/projects.js 44 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/roomRecord.js 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/roomTime.js 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/meeting/rooms.js 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/api/system/dictData.js 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/base/BaseOpera.vue 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/base/BaseTable.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaCarsWindow.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaCompanyWindow.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/business/OperaInternalCompanyWindow.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/RichEditor.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadAvatarImage.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadAvatarVideo.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadFile.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadFileCommon.vue 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/UploadImage.vue 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/upload.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/visitorSources.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/bookings.vue 310 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaBookingsDetailWindow.vue 164 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaBookingsWindow.vue 442 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaDevicesWindow.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaNoticeWindow.vue 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaProjectsWindow.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaRoomRecordWindow.vue 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/OperaRoomsWindow.vue 275 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/common/FileLink.vue 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/common/FileLinkItem.vue 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/common/PDFPreview.vue 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/components/selectMember.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/devices.vue 156 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/notice.vue 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/projects.vue 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/roomRecord.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/roomStatistics.vue 230 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/rooms.vue 236 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/userStatistics.vue 245 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
replay_pid19008.log 12057 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
replay_pid30652.log 11987 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/api/common/CaptchaController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/api/common/PublicController.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/BookingTimeCloudController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/BookingsCloudController.java 75 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/MeetingCloudController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/MultifileCloudController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/ProjectRelCloudController.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/ProjectsCloudController.java 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/RoomsCloudController.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/UserRelCloudController.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/resources/bootstrap.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/resources/logback-spring.xml 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/BookingTime.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Bookings.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Devices.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/ProjectRel.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Projects.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/RoomRecord.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/RoomTime.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Rooms.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/UserRel.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/web/request/BookingsRequest.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/service/business/BookingsService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/BookingsServiceImpl.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/ProjectsServiceImpl.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/RoomsServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/pom.xml 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_gateway/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/config/cloudfilter/LoginHandlerInterceptor.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/Constants.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/Multifile.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/Notices.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDataPermission.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDepartment.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDepartmentUser.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDict.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDictData.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemLoginLog.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemMenu.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPermission.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPosition.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPositionUser.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRole.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRoleMenu.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRolePermission.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemTraceLog.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemUser.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/dao/system/model/SystemUserRole.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/common/PublicCloudController.java 334 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarBook.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarParks.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarUseBook.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Member.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Parks.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Platform.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Visits.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package-lock.json
@@ -1295,6 +1295,11 @@
      "integrity": "sha1-pTUV2yXYA4N0OBtzryC7Ty5QjYc=",
      "dev": true
    },
    "@transloadit/prettier-bytes": {
      "version": "0.0.7",
      "resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
      "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA=="
    },
    "@types/anymatch": {
      "version": "1.3.1",
      "resolved": "https://registry.npm.taobao.org/@types/anymatch/download/@types/anymatch-1.3.1.tgz?cache=0&sync_timestamp=1613378060592&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fanymatch%2Fdownload%2F%40types%2Fanymatch-1.3.1.tgz",
@@ -1329,6 +1334,11 @@
        "@types/express-serve-static-core": "*",
        "@types/node": "*"
      }
    },
    "@types/event-emitter": {
      "version": "0.3.5",
      "resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.5.tgz",
      "integrity": "sha512-zx2/Gg0Eg7gwEiOIIh5w9TrhKKTeQh7CPCOPNc0el4pLSwzebA8SmnHwZs2dWlLONvyulykSwGSQxQHLhjGLvQ=="
    },
    "@types/express": {
      "version": "4.17.11",
@@ -1523,6 +1533,53 @@
          "integrity": "sha1-UwL4FpAxc1ImVECS5kmB91F1A4M=",
          "dev": true
        }
      }
    },
    "@uppy/companion-client": {
      "version": "2.2.2",
      "resolved": "https://registry.npmmirror.com/@uppy/companion-client/-/companion-client-2.2.2.tgz",
      "integrity": "sha512-5mTp2iq97/mYSisMaBtFRry6PTgZA6SIL7LePteOV5x0/DxKfrZW3DEiQERJmYpHzy7k8johpm2gHnEKto56Og==",
      "requires": {
        "@uppy/utils": "^4.1.2",
        "namespace-emitter": "^2.0.1"
      }
    },
    "@uppy/core": {
      "version": "2.3.4",
      "resolved": "https://registry.npmmirror.com/@uppy/core/-/core-2.3.4.tgz",
      "integrity": "sha512-iWAqppC8FD8mMVqewavCz+TNaet6HPXitmGXpGGREGrakZ4FeuWytVdrelydzTdXx6vVKkOmI2FLztGg73sENQ==",
      "requires": {
        "@transloadit/prettier-bytes": "0.0.7",
        "@uppy/store-default": "^2.1.1",
        "@uppy/utils": "^4.1.3",
        "lodash.throttle": "^4.1.1",
        "mime-match": "^1.0.2",
        "namespace-emitter": "^2.0.1",
        "nanoid": "^3.1.25",
        "preact": "^10.5.13"
      }
    },
    "@uppy/store-default": {
      "version": "2.1.1",
      "resolved": "https://registry.npmmirror.com/@uppy/store-default/-/store-default-2.1.1.tgz",
      "integrity": "sha512-xnpTxvot2SeAwGwbvmJ899ASk5tYXhmZzD/aCFsXePh/v8rNvR2pKlcQUH7cF/y4baUGq3FHO/daKCok/mpKqQ=="
    },
    "@uppy/utils": {
      "version": "4.1.3",
      "resolved": "https://registry.npmmirror.com/@uppy/utils/-/utils-4.1.3.tgz",
      "integrity": "sha512-nTuMvwWYobnJcytDO3t+D6IkVq/Qs4Xv3vyoEZ+Iaf8gegZP+rEyoaFT2CK5XLRMienPyqRqNbIfRuFaOWSIFw==",
      "requires": {
        "lodash.throttle": "^4.1.1"
      }
    },
    "@uppy/xhr-upload": {
      "version": "2.1.3",
      "resolved": "https://registry.npmmirror.com/@uppy/xhr-upload/-/xhr-upload-2.1.3.tgz",
      "integrity": "sha512-YWOQ6myBVPs+mhNjfdWsQyMRWUlrDLMoaG7nvf/G6Y3GKZf8AyjFDjvvJ49XWQ+DaZOftGkHmF1uh/DBeGivJQ==",
      "requires": {
        "@uppy/companion-client": "^2.2.2",
        "@uppy/utils": "^4.1.2",
        "nanoid": "^3.1.25"
      }
    },
    "@vue/babel-helper-vue-jsx-merge-props": {
@@ -1998,6 +2055,88 @@
      "resolved": "https://registry.npm.taobao.org/@vue/web-component-wrapper/download/@vue/web-component-wrapper-1.3.0.tgz",
      "integrity": "sha1-trQKdiVCnSvXwigd26YB7QXcfxo=",
      "dev": true
    },
    "@wangeditor/basic-modules": {
      "version": "1.1.7",
      "resolved": "https://registry.npmmirror.com/@wangeditor/basic-modules/-/basic-modules-1.1.7.tgz",
      "integrity": "sha512-cY9CPkLJaqF05STqfpZKWG4LpxTMeGSIIF1fHvfm/mz+JXatCagjdkbxdikOuKYlxDdeqvOeBmsUBItufDLXZg==",
      "requires": {
        "is-url": "^1.2.4"
      }
    },
    "@wangeditor/code-highlight": {
      "version": "1.0.3",
      "resolved": "https://registry.npmmirror.com/@wangeditor/code-highlight/-/code-highlight-1.0.3.tgz",
      "integrity": "sha512-iazHwO14XpCuIWJNTQTikqUhGKyqj+dUNWJ9288Oym9M2xMVHvnsOmDU2sgUDWVy+pOLojReMPgXCsvvNlOOhw==",
      "requires": {
        "prismjs": "^1.23.0"
      }
    },
    "@wangeditor/core": {
      "version": "1.1.19",
      "resolved": "https://registry.npmmirror.com/@wangeditor/core/-/core-1.1.19.tgz",
      "integrity": "sha512-KevkB47+7GhVszyYF2pKGKtCSj/YzmClsD03C3zTt+9SR2XWT5T0e3yQqg8baZpcMvkjs1D8Dv4fk8ok/UaS2Q==",
      "requires": {
        "@types/event-emitter": "^0.3.3",
        "event-emitter": "^0.3.5",
        "html-void-elements": "^2.0.0",
        "i18next": "^20.4.0",
        "scroll-into-view-if-needed": "^2.2.28",
        "slate-history": "^0.66.0"
      }
    },
    "@wangeditor/editor": {
      "version": "5.1.23",
      "resolved": "https://registry.npmmirror.com/@wangeditor/editor/-/editor-5.1.23.tgz",
      "integrity": "sha512-0RxfeVTuK1tktUaPROnCoFfaHVJpRAIE2zdS0mpP+vq1axVQpLjM8+fCvKzqYIkH0Pg+C+44hJpe3VVroSkEuQ==",
      "requires": {
        "@uppy/core": "^2.1.1",
        "@uppy/xhr-upload": "^2.0.3",
        "@wangeditor/basic-modules": "^1.1.7",
        "@wangeditor/code-highlight": "^1.0.3",
        "@wangeditor/core": "^1.1.19",
        "@wangeditor/list-module": "^1.0.5",
        "@wangeditor/table-module": "^1.1.4",
        "@wangeditor/upload-image-module": "^1.0.2",
        "@wangeditor/video-module": "^1.1.4",
        "dom7": "^3.0.0",
        "is-hotkey": "^0.2.0",
        "lodash.camelcase": "^4.3.0",
        "lodash.clonedeep": "^4.5.0",
        "lodash.debounce": "^4.0.8",
        "lodash.foreach": "^4.5.0",
        "lodash.isequal": "^4.5.0",
        "lodash.throttle": "^4.1.1",
        "lodash.toarray": "^4.4.0",
        "nanoid": "^3.2.0",
        "slate": "^0.72.0",
        "snabbdom": "^3.1.0"
      }
    },
    "@wangeditor/editor-for-vue": {
      "version": "5.1.12",
      "resolved": "https://registry.npmmirror.com/@wangeditor/editor-for-vue/-/editor-for-vue-5.1.12.tgz",
      "integrity": "sha512-0Ds3D8I+xnpNWezAeO7HmPRgTfUxHLMd9JKcIw+QzvSmhC5xUHbpCcLU+KLmeBKTR/zffnS5GQo6qi3GhTMJWQ=="
    },
    "@wangeditor/list-module": {
      "version": "1.0.5",
      "resolved": "https://registry.npmmirror.com/@wangeditor/list-module/-/list-module-1.0.5.tgz",
      "integrity": "sha512-uDuYTP6DVhcYf7mF1pTlmNn5jOb4QtcVhYwSSAkyg09zqxI1qBqsfUnveeDeDqIuptSJhkh81cyxi+MF8sEPOQ=="
    },
    "@wangeditor/table-module": {
      "version": "1.1.4",
      "resolved": "https://registry.npmmirror.com/@wangeditor/table-module/-/table-module-1.1.4.tgz",
      "integrity": "sha512-5saanU9xuEocxaemGdNi9t8MCDSucnykEC6jtuiT72kt+/Hhh4nERYx1J20OPsTCCdVr7hIyQenFD1iSRkIQ6w=="
    },
    "@wangeditor/upload-image-module": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/@wangeditor/upload-image-module/-/upload-image-module-1.0.2.tgz",
      "integrity": "sha512-z81lk/v71OwPDYeQDxj6cVr81aDP90aFuywb8nPD6eQeECtOymrqRODjpO6VGvCVxVck8nUxBHtbxKtjgcwyiA=="
    },
    "@wangeditor/video-module": {
      "version": "1.1.4",
      "resolved": "https://registry.npmmirror.com/@wangeditor/video-module/-/video-module-1.1.4.tgz",
      "integrity": "sha512-ZdodDPqKQrgx3IwWu4ZiQmXI8EXZ3hm2/fM6E3t5dB8tCaIGWQZhmqd6P5knfkRAd3z2+YRSRbxOGfoRSp/rLg=="
    },
    "@webassemblyjs/ast": {
      "version": "1.9.0",
@@ -3796,6 +3935,11 @@
        }
      }
    },
    "compute-scroll-into-view": {
      "version": "1.0.20",
      "resolved": "https://registry.npmmirror.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz",
      "integrity": "sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg=="
    },
    "concat-map": {
      "version": "0.0.1",
      "resolved": "https://registry.npm.taobao.org/concat-map/download/concat-map-0.0.1.tgz",
@@ -4438,6 +4582,15 @@
      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
      "dev": true
    },
    "d": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/d/-/d-1.0.2.tgz",
      "integrity": "sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==",
      "requires": {
        "es5-ext": "^0.10.64",
        "type": "^2.7.2"
      }
    },
    "dashdash": {
      "version": "1.14.1",
      "resolved": "https://registry.npm.taobao.org/dashdash/download/dashdash-1.14.1.tgz?cache=0&sync_timestamp=1601073454623&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdashdash%2Fdownload%2Fdashdash-1.14.1.tgz",
@@ -4857,6 +5010,14 @@
        }
      }
    },
    "dom7": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/dom7/-/dom7-3.0.0.tgz",
      "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==",
      "requires": {
        "ssr-window": "^3.0.0-alpha.1"
      }
    },
    "domain-browser": {
      "version": "1.2.0",
      "resolved": "https://registry.npm.taobao.org/domain-browser/download/domain-browser-1.2.0.tgz?cache=0&sync_timestamp=1604239998047&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomain-browser%2Fdownload%2Fdomain-browser-1.2.0.tgz",
@@ -5156,6 +5317,36 @@
        "is-callable": "^1.1.4",
        "is-date-object": "^1.0.1",
        "is-symbol": "^1.0.2"
      }
    },
    "es5-ext": {
      "version": "0.10.64",
      "resolved": "https://registry.npmmirror.com/es5-ext/-/es5-ext-0.10.64.tgz",
      "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==",
      "requires": {
        "es6-iterator": "^2.0.3",
        "es6-symbol": "^3.1.3",
        "esniff": "^2.0.1",
        "next-tick": "^1.1.0"
      }
    },
    "es6-iterator": {
      "version": "2.0.3",
      "resolved": "https://registry.npmmirror.com/es6-iterator/-/es6-iterator-2.0.3.tgz",
      "integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
      "requires": {
        "d": "1",
        "es5-ext": "^0.10.35",
        "es6-symbol": "^3.1.1"
      }
    },
    "es6-symbol": {
      "version": "3.1.4",
      "resolved": "https://registry.npmmirror.com/es6-symbol/-/es6-symbol-3.1.4.tgz",
      "integrity": "sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==",
      "requires": {
        "d": "^1.0.2",
        "ext": "^1.7.0"
      }
    },
    "escalade": {
@@ -5675,6 +5866,17 @@
      "integrity": "sha1-MOvR73wv3/AcOk8VEESvJfqwUj4=",
      "dev": true
    },
    "esniff": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/esniff/-/esniff-2.0.1.tgz",
      "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==",
      "requires": {
        "d": "^1.0.1",
        "es5-ext": "^0.10.62",
        "event-emitter": "^0.3.5",
        "type": "^2.7.2"
      }
    },
    "espree": {
      "version": "6.2.1",
      "resolved": "https://registry.npm.taobao.org/espree/download/espree-6.2.1.tgz?cache=0&sync_timestamp=1607143966756&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fespree%2Fdownload%2Fespree-6.2.1.tgz",
@@ -5751,6 +5953,15 @@
      "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz",
      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
      "dev": true
    },
    "event-emitter": {
      "version": "0.3.5",
      "resolved": "https://registry.npmmirror.com/event-emitter/-/event-emitter-0.3.5.tgz",
      "integrity": "sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==",
      "requires": {
        "d": "1",
        "es5-ext": "~0.10.14"
      }
    },
    "event-pubsub": {
      "version": "4.3.0",
@@ -5913,6 +6124,14 @@
          "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=",
          "dev": true
        }
      }
    },
    "ext": {
      "version": "1.7.0",
      "resolved": "https://registry.npmmirror.com/ext/-/ext-1.7.0.tgz",
      "integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
      "requires": {
        "type": "^2.7.2"
      }
    },
    "extend": {
@@ -6857,6 +7076,11 @@
      "integrity": "sha1-e15vfmZen7QfMAB+2eDUHpf7IUA=",
      "dev": true
    },
    "html-void-elements": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/html-void-elements/-/html-void-elements-2.0.1.tgz",
      "integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A=="
    },
    "html-webpack-plugin": {
      "version": "3.2.0",
      "resolved": "https://registry.npm.taobao.org/html-webpack-plugin/download/html-webpack-plugin-3.2.0.tgz?cache=0&sync_timestamp=1615296040860&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhtml-webpack-plugin%2Fdownload%2Fhtml-webpack-plugin-3.2.0.tgz",
@@ -7072,6 +7296,14 @@
      "integrity": "sha1-xbHNFPUK6uCatsWf5jujOV/k36M=",
      "dev": true
    },
    "i18next": {
      "version": "20.6.1",
      "resolved": "https://registry.npmmirror.com/i18next/-/i18next-20.6.1.tgz",
      "integrity": "sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A==",
      "requires": {
        "@babel/runtime": "^7.12.0"
      }
    },
    "iconv-lite": {
      "version": "0.4.24",
      "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184264130&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz",
@@ -7107,6 +7339,11 @@
      "resolved": "https://registry.npm.taobao.org/ignore/download/ignore-4.0.6.tgz?cache=0&sync_timestamp=1590809289115&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fignore%2Fdownload%2Fignore-4.0.6.tgz",
      "integrity": "sha1-dQ49tYYgh7RzfrrIIH/9HvJ7Jfw=",
      "dev": true
    },
    "immer": {
      "version": "9.0.21",
      "resolved": "https://registry.npmmirror.com/immer/-/immer-9.0.21.tgz",
      "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA=="
    },
    "import-cwd": {
      "version": "2.1.0",
@@ -7589,6 +7826,11 @@
        "is-extglob": "^2.1.1"
      }
    },
    "is-hotkey": {
      "version": "0.2.0",
      "resolved": "https://registry.npmmirror.com/is-hotkey/-/is-hotkey-0.2.0.tgz",
      "integrity": "sha512-UknnZK4RakDmTgz4PI1wIph5yxSs/mvChWs9ifnlXsKuXgWmOkY/hAE0H/k2MIqH0RlRye0i1oC07MCRSD28Mw=="
    },
    "is-negative-zero": {
      "version": "2.0.1",
      "resolved": "https://registry.npm.taobao.org/is-negative-zero/download/is-negative-zero-2.0.1.tgz?cache=0&sync_timestamp=1607123080624&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fis-negative-zero%2Fdownload%2Fis-negative-zero-2.0.1.tgz",
@@ -7728,6 +7970,11 @@
      "resolved": "https://registry.npm.taobao.org/is-typedarray/download/is-typedarray-1.0.0.tgz",
      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
      "dev": true
    },
    "is-url": {
      "version": "1.2.4",
      "resolved": "https://registry.npmmirror.com/is-url/-/is-url-1.2.4.tgz",
      "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww=="
    },
    "is-utf8": {
      "version": "0.2.1",
@@ -8495,17 +8742,36 @@
      "resolved": "https://registry.npm.taobao.org/lodash/download/lodash-4.17.21.tgz",
      "integrity": "sha1-Z5WRxWTDv/quhFTPCz3zcMPWkRw="
    },
    "lodash.camelcase": {
      "version": "4.3.0",
      "resolved": "https://registry.npmmirror.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
      "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="
    },
    "lodash.clonedeep": {
      "version": "4.5.0",
      "resolved": "https://registry.npmmirror.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
      "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ=="
    },
    "lodash.debounce": {
      "version": "4.0.8",
      "resolved": "https://registry.npm.taobao.org/lodash.debounce/download/lodash.debounce-4.0.8.tgz",
      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
      "dev": true
      "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
    },
    "lodash.defaultsdeep": {
      "version": "4.6.1",
      "resolved": "https://registry.npm.taobao.org/lodash.defaultsdeep/download/lodash.defaultsdeep-4.6.1.tgz",
      "integrity": "sha1-US6b1yHSctlOPTpjZT+hdRZ0HKY=",
      "dev": true
    },
    "lodash.foreach": {
      "version": "4.5.0",
      "resolved": "https://registry.npmmirror.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
      "integrity": "sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ=="
    },
    "lodash.isequal": {
      "version": "4.5.0",
      "resolved": "https://registry.npmmirror.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
    },
    "lodash.kebabcase": {
      "version": "4.1.1",
@@ -8524,6 +8790,16 @@
      "resolved": "https://registry.npm.taobao.org/lodash.memoize/download/lodash.memoize-4.1.2.tgz",
      "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
      "dev": true
    },
    "lodash.throttle": {
      "version": "4.1.1",
      "resolved": "https://registry.npmmirror.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
      "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
    },
    "lodash.toarray": {
      "version": "4.4.0",
      "resolved": "https://registry.npmmirror.com/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
      "integrity": "sha512-QyffEA3i5dma5q2490+SgCvDN0pXLmRGSyAANuVi0HQ01Pkfr9fuoKQW8wm1wGBnJITs/mS7wQvS6VshUEBFCw=="
    },
    "lodash.transform": {
      "version": "4.6.0",
@@ -8914,6 +9190,14 @@
      "integrity": "sha1-jLMT5Zll08Bc+/iYkVomevRqM1w=",
      "dev": true
    },
    "mime-match": {
      "version": "1.0.2",
      "resolved": "https://registry.npmmirror.com/mime-match/-/mime-match-1.0.2.tgz",
      "integrity": "sha512-VXp/ugGDVh3eCLOBCiHZMYWQaTNUHv2IJrut+yXA6+JbLPXHglHwfS/5A5L0ll+jkCY7fIzRJcH6OIunF+c6Cg==",
      "requires": {
        "wildcard": "^1.1.0"
      }
    },
    "mime-types": {
      "version": "2.1.30",
      "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.30.tgz",
@@ -9111,11 +9395,21 @@
        "thenify-all": "^1.0.0"
      }
    },
    "namespace-emitter": {
      "version": "2.0.1",
      "resolved": "https://registry.npmmirror.com/namespace-emitter/-/namespace-emitter-2.0.1.tgz",
      "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g=="
    },
    "nan": {
      "version": "2.14.2",
      "resolved": "https://registry.npm.taobao.org/nan/download/nan-2.14.2.tgz?cache=0&sync_timestamp=1602591684976&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnan%2Fdownload%2Fnan-2.14.2.tgz",
      "integrity": "sha1-9TdkAGlRaPTMaUrJOT0MlYXu6hk=",
      "dev": true
    },
    "nanoid": {
      "version": "3.3.7",
      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz",
      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g=="
    },
    "nanomatch": {
      "version": "1.2.13",
@@ -9153,6 +9447,11 @@
      "resolved": "https://registry.npm.taobao.org/neo-async/download/neo-async-2.6.2.tgz?cache=0&sync_timestamp=1594317434347&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fneo-async%2Fdownload%2Fneo-async-2.6.2.tgz",
      "integrity": "sha1-tKr7k+OustgXTKU88WOrfXMIMF8=",
      "dev": true
    },
    "next-tick": {
      "version": "1.1.0",
      "resolved": "https://registry.npmmirror.com/next-tick/-/next-tick-1.1.0.tgz",
      "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
    },
    "nice-try": {
      "version": "1.0.5",
@@ -10690,6 +10989,11 @@
      "integrity": "sha1-RD9qIM7WSBor2k+oUypuVdeJoss=",
      "dev": true
    },
    "preact": {
      "version": "10.21.0",
      "resolved": "https://registry.npmmirror.com/preact/-/preact-10.21.0.tgz",
      "integrity": "sha512-aQAIxtzWEwH8ou+OovWVSVNlFImL7xUCwJX3YMqA3U8iKCNC34999fFOnWjYNsylgfPgMexpbk7WYOLtKr/mxg=="
    },
    "prelude-ls": {
      "version": "1.1.2",
      "resolved": "https://registry.npm.taobao.org/prelude-ls/download/prelude-ls-1.1.2.tgz",
@@ -10718,6 +11022,11 @@
        "lodash": "^4.17.20",
        "renderkid": "^2.0.4"
      }
    },
    "prismjs": {
      "version": "1.29.0",
      "resolved": "https://registry.npmmirror.com/prismjs/-/prismjs-1.29.0.tgz",
      "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q=="
    },
    "process": {
      "version": "0.11.10",
@@ -11711,6 +12020,14 @@
        "ajv-keywords": "^3.5.2"
      }
    },
    "scroll-into-view-if-needed": {
      "version": "2.2.31",
      "resolved": "https://registry.npmmirror.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz",
      "integrity": "sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==",
      "requires": {
        "compute-scroll-into-view": "^1.0.20"
      }
    },
    "scss-tokenizer": {
      "version": "0.2.3",
      "resolved": "https://registry.npm.taobao.org/scss-tokenizer/download/scss-tokenizer-0.2.3.tgz",
@@ -12003,6 +12320,38 @@
      "integrity": "sha1-3lUoUaF1nfOo8gZTVEL17E3eq0Q=",
      "dev": true
    },
    "slate": {
      "version": "0.72.8",
      "resolved": "https://registry.npmmirror.com/slate/-/slate-0.72.8.tgz",
      "integrity": "sha512-/nJwTswQgnRurpK+bGJFH1oM7naD5qDmHd89JyiKNT2oOKD8marW0QSBtuFnwEbL5aGCS8AmrhXQgNOsn4osAw==",
      "requires": {
        "immer": "^9.0.6",
        "is-plain-object": "^5.0.0",
        "tiny-warning": "^1.0.3"
      },
      "dependencies": {
        "is-plain-object": {
          "version": "5.0.0",
          "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
          "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
        }
      }
    },
    "slate-history": {
      "version": "0.66.0",
      "resolved": "https://registry.npmmirror.com/slate-history/-/slate-history-0.66.0.tgz",
      "integrity": "sha512-6MWpxGQZiMvSINlCbMW43E2YBSVMCMCIwQfBzGssjWw4kb0qfvj0pIdblWNRQZD0hR6WHP+dHHgGSeVdMWzfng==",
      "requires": {
        "is-plain-object": "^5.0.0"
      },
      "dependencies": {
        "is-plain-object": {
          "version": "5.0.0",
          "resolved": "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-5.0.0.tgz",
          "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
        }
      }
    },
    "slice-ansi": {
      "version": "2.1.0",
      "resolved": "https://registry.npm.taobao.org/slice-ansi/download/slice-ansi-2.1.0.tgz?cache=0&sync_timestamp=1618554953055&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fslice-ansi%2Fdownload%2Fslice-ansi-2.1.0.tgz",
@@ -12021,6 +12370,11 @@
          "dev": true
        }
      }
    },
    "snabbdom": {
      "version": "3.6.2",
      "resolved": "https://registry.npmmirror.com/snabbdom/-/snabbdom-3.6.2.tgz",
      "integrity": "sha512-ig5qOnCDbugFntKi6c7Xlib8bA6xiJVk8O+WdFrV3wxbMqeHO0hXFQC4nAhPVWfZfi8255lcZkNhtIBINCc4+Q=="
    },
    "snapdragon": {
      "version": "0.8.2",
@@ -12349,6 +12703,11 @@
        "safer-buffer": "^2.0.2",
        "tweetnacl": "~0.14.0"
      }
    },
    "ssr-window": {
      "version": "3.0.0",
      "resolved": "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz",
      "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA=="
    },
    "ssri": {
      "version": "6.0.2",
@@ -12900,6 +13259,11 @@
      "resolved": "https://registry.npm.taobao.org/tiny-emitter/download/tiny-emitter-2.1.0.tgz",
      "integrity": "sha1-HRpW7fxRxD6GPLtTgqcjMONVVCM="
    },
    "tiny-warning": {
      "version": "1.0.3",
      "resolved": "https://registry.npmmirror.com/tiny-warning/-/tiny-warning-1.0.3.tgz",
      "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
    },
    "tiptap": {
      "version": "1.32.2",
      "resolved": "https://registry.npmjs.org/tiptap/-/tiptap-1.32.2.tgz",
@@ -13120,6 +13484,11 @@
      "resolved": "https://registry.npm.taobao.org/tweetnacl/download/tweetnacl-0.14.5.tgz?cache=0&sync_timestamp=1581364203962&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftweetnacl%2Fdownload%2Ftweetnacl-0.14.5.tgz",
      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
      "dev": true
    },
    "type": {
      "version": "2.7.2",
      "resolved": "https://registry.npmmirror.com/type/-/type-2.7.2.tgz",
      "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
    },
    "type-check": {
      "version": "0.3.2",
@@ -14363,6 +14732,11 @@
        }
      }
    },
    "wildcard": {
      "version": "1.1.2",
      "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
      "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
    },
    "word-wrap": {
      "version": "1.2.3",
      "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz",
admin/package.json
@@ -11,6 +11,8 @@
  },
  "dependencies": {
    "@riophae/vue-treeselect": "^0.4.0",
    "@wangeditor/editor": "^5.1.23",
    "@wangeditor/editor-for-vue": "^5.1.12",
    "axios": "^0.21.1",
    "core-js": "^3.6.5",
    "echarts": "^5.4.3",
admin/src/api/meeting/bookings.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/bookings/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/bookings/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/bookings/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/bookings/updateById', data)
}
// å–消
export function cancelById (data) {
  debugger
  return request.post('/meetingAdmin/cloudService/business/bookings/cancelById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/business/bookings/delete/${id}`)
}
// æ ¹æ®ID查询
export function bookingsDetail (id) {
  return request.get(`/meetingAdmin/cloudService/business/bookings/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/bookings/delete/batch', {
    params: {
      ids
    }
  })
}
// ä¼šè®®å®¤ä½¿ç”¨æ—¶é•¿ç»Ÿè®¡
export function getRoomStatistics (yearNum, roomId) {
  return request.get(`/meetingAdmin/cloudService/business/bookings/getRoomStatistics?yearNum=${yearNum}&roomId=${roomId}`)
}
// ä¼šè®®å®¤ä½¿ç”¨æ—¶é•¿ç»Ÿè®¡å¯¼å‡ºExcel
export function exportRoomStatistics (data) {
  return request.post(`/meetingAdmin/cloudService/business/bookings/exportRoomStatistics`, data, {
    trim: true,
    download: true
  })
}
// äººå‘˜å‚加会议时常
export function getUserStatistics (data) {
  return request.post(`/meetingAdmin/cloudService/business/bookings/getUserStatistics`, data)
}
// äººå‘˜å‚会时长统计导出Excel
export function exportUserStatistics (data) {
  return request.post(`/meetingAdmin/cloudService/business/bookings/exportUserStatistics`, data, {
    trim: true,
    download: true
  })
}
//
export function reservationCancel (type) {
  return request.get(`/meetingAdmin/cloudService/business/bookings/reservationCancel?type=${type}`)
}
//
export function findMothBookingMeet ({roomId, dateMonth}) {
  return request.post(`/meetingAdmin/cloudService/business/bookings/findMothBookingMeet?roomId=${roomId}&dateMonth=${dateMonth}`)
}
admin/src/api/meeting/devices.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/devices/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/devices/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/devices/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/devices/updateById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/business/devices/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/devices/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/meeting/home.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,7 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function home (data) {
  return request.post('/meetingAdmin/cloudService/business/home/home', data, {
    trim: true
  })
}
admin/src/api/meeting/notice.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/notice/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/notice/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/notice/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/notice/updateById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/notice/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/notice/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/meeting/projects.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,44 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/projects/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/projects/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/projects/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/projects/updateById', data)
}
// ä¼šè®®å…³è”的项目
export function findListByObjId ({objId, objType}) {
  // return request.post('/meetingAdmin/cloudService/business/projects/findListByObjId', { params })
  return request.post(`/meetingAdmin/cloudService/projects/findListByObjId?objId=${objId}&objType=${objType}`)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/projects/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/projects/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/meeting/roomRecord.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/roomRecord/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/roomRecord/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/roomRecord/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/roomRecord/updateById', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/roomRecord/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/roomRecord/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/meeting/roomTime.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,5 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function findList (data) {
  return request.post('/meetingAdmin/cloudService/business/roomTime/findList', data)
}
admin/src/api/meeting/rooms.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
import request from '../../utils/request'
// æŸ¥è¯¢
export function fetchList (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/page', data, {
    trim: true
  })
}
// å¯¼å‡ºExcel
export function exportExcel (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/exportExcel', data, {
    trim: true,
    download: true
  })
}
// åˆ›å»º
export function create (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/create', data)
}
// ä¿®æ”¹
export function updateById (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/updateById', data)
}
// ä¿®æ”¹çŠ¶æ€
export function updateStatusById (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/updateStatusById', data)
}
//
export function findList (data) {
  return request.post('/meetingAdmin/cloudService/business/rooms/findList', data)
}
// åˆ é™¤
export function deleteById (id) {
  return request.get(`/meetingAdmin/cloudService/rooms/delete/${id}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/meetingAdmin/cloudService/business/rooms/delete/batch', {
    params: {
      ids
    }
  })
}
admin/src/api/system/dictData.js
@@ -19,7 +19,10 @@
export function deleteById (id) {
  return request.get(`/visitsAdmin/cloudService/system/dictData/delete/${id}`)
}
// æŸ¥è¯¢å­—典值数据
export function getSystemDictData (label) {
  return request.get(`/visitsAdmin/cloudService/system/dictData/getSystemDictData?dictCode=SYSTEM&label=${label}`)
}
// æ‰¹é‡åˆ é™¤
export function deleteByIdInBatch (ids) {
  return request.get('/system/dictData/delete/batch', {
admin/src/components/base/BaseOpera.vue
@@ -33,7 +33,11 @@
      if (extParams.api == null) {
        throw new Error('Missing config option \'api\'.')
      }
      this.api = require('@/api' + extParams.api)
      if(extParams.api.indexOf('@/',0) === 0){
        this.api = require(extParams.api)
      }else {
        this.api = require('@/api' + extParams.api)
      }
      extParams['field.id'] && (this.configData['field.id'] = extParams['field.id'])
    },
    /**
admin/src/components/base/BaseTable.vue
@@ -51,7 +51,13 @@
      if (extParams.api == null) {
        throw new Error('Missing config option \'api\'.')
      }
      this.api = require('@/api' + extParams.api)
      if(extParams.api.indexOf('@/',0) === 0){
        this.api = require(extParams.api)
      }else {
        this.api = require('@/api' + extParams.api)
      }
      // this.api = require('@/api' + extParams.api)
      extParams.module && (this.module = extParams.module)
      extParams['field.id'] && (this.configData['field.id'] = extParams['field.id'])
      extParams['field.main'] && (this.configData['field.main'] = extParams['field.main'])
admin/src/components/business/OperaCarsWindow.vue
@@ -67,7 +67,7 @@
  },
  created () {
    this.config({
      api: '/business/cars',
      api: '/business/parkBook',
      'field.id': 'id'
    })
  }
admin/src/components/business/OperaCompanyWindow.vue
@@ -56,7 +56,7 @@
  },
  created () {
    this.config({
      api: '/business/company',
      api: '/business/company.js',
      'field.id': 'id'
    })
  }
admin/src/components/business/OperaInternalCompanyWindow.vue
@@ -63,7 +63,7 @@
  },
  created () {
    this.config({
      api: '/business/company',
      api: '/business/company.js',
      'field.id': 'id'
    })
  },
admin/src/components/common/RichEditor.vue
@@ -111,7 +111,7 @@
          uploadImage: {
            // server: '/api/upload',
            name: 'file',
            server: process.env.VUE_APP_API_PREFIX + '/public/uploadLocal',
            server: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/uploadLocal',
            meta: {
              folder: 'shop'
            },
admin/src/components/common/UploadAvatarImage.vue
@@ -36,7 +36,7 @@
  },
  data() {
    return {
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload'
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload'
    }
  },
@@ -50,13 +50,13 @@
        this.$message.success('上传成功')
        this.$emit('uploadSuccess', { imgurl: data.imgaddr, imgurlfull: data.url, name: data.originname })
      } else {
        this.$tip.apiFailed('上传失败')
        this.$message.error('上传失败')
      }
      this.$emit('uploadEnd')
    },
    uploadError() {
      this.$tip.apiFailed('上传失败')
      this.$emit('endUpload')
      this.$message.error('上传失败')
      this.$emit('uploadEnd')
    },
    // // æ‹¦æˆª
    beforeAvatarUpload(file) {
admin/src/components/common/UploadAvatarVideo.vue
@@ -36,7 +36,7 @@
  },
  data() {
    return {
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload'
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload'
    }
  },
@@ -50,13 +50,13 @@
        this.$message.success('上传成功')
        this.$emit('uploadSuccess', { imgurl: data.imgaddr, imgurlfull: data.url, name: data.originname })
      } else {
        this.$tip.apiFailed('上传失败')
        this.$message.error('上传失败')
      }
      this.$emit('uploadEnd')
    },
    uploadError() {
      this.$tip.apiFailed('上传失败')
      this.$emit('endUpload')
      this.$message.apiFailed('上传失败')
      this.$emit('uploadEnd')
    },
    // // æ‹¦æˆª
    beforeAvatarUpload(file) {
admin/src/components/common/UploadFile.vue
@@ -34,7 +34,7 @@
  data() {
    return {
      fileList:null,
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload?folder='+this.uploadData.folder
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload?folder='+this.uploadData.folder
    }
  },
@@ -48,13 +48,13 @@
        this.$message.success('上传成功')
        this.$emit('uploadSuccess', { fileurl: data.imgaddr, fileurlFull: data.url, name: data.originname })
      } else {
        this.$tip.apiFailed('上传失败')
        this.$message.error('上传失败')
      }
      this.$emit('uploadEnd')
    },
    uploadError() {
      this.$tip.apiFailed('上传失败')
      this.$emit('endUpload')
      this.$message.error('上传失败')
      this.$emit('uploadEnd')
    },
    // // æ‹¦æˆª
    beforeFileUpload(file) {
admin/src/components/common/UploadFileCommon.vue
@@ -39,7 +39,7 @@
  },
  data() {
    return {
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload'
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload'
    }
  },
@@ -55,13 +55,13 @@
        this.$message.success('上传成功')
        this.$emit('uploadSuccess', { fileurl: data.imgaddr, fileUrlFull: data.url, name: data.originname })
      } else {
        this.$tip.apiFailed('上传失败')
        this.$message.error('上传失败')
      }
      this.$emit('uploadEnd')
    },
    uploadError() {
      this.$tip.apiFailed('上传失败')
      this.$emit('endUpload')
      this.$message.error('上传失败')
      this.$emit('uploadEnd')
    },
    // // æ‹¦æˆª
    beforeAvatarUpload(file) {
@@ -147,4 +147,4 @@
  width: 90px !important;
  height: 90px !important;
}
</style>
</style>
admin/src/components/common/UploadImage.vue
@@ -33,15 +33,15 @@
        </span>
      </div>
    </el-upload>
    <el-image-viewer
      v-if="showViewer"
    <el-image-viewer
      v-if="showViewer"
      :on-close="closeViewer"
      :initialIndex="tempIndex"
      :url-list="srcList"
      :z-index="3000"
    />
  </div>
</template>
<script>
@@ -59,8 +59,8 @@
  },
  data() {
    return {
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/uploadLocal',
      uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/uploadLocal',
      realList: [],
      srcList: [],
      tempIndex: 0,
@@ -76,20 +76,20 @@
          this.srcList = []
        }
      }
    }
  },
  methods: {
    beforeUpload(file) {
      this.$emit('beginUpload')
      return true
    },
     // ä¸Šä¼ å›¾ç‰‡æˆåŠŸ
     uploadSuccess (res, file, fileList) {
     uploadSuccess (res, file, fileList) {
      // console.log('this.fileList', this.fileList);
      // console.log('fileList', fileList);
      this.$emit('endUpload')
      this.$emit('uploadEnd')
      this.realList = fileList
      this.srcList.push(res.data.url)
      // console.log('file', file);
@@ -106,7 +106,7 @@
      }
    },
    fail (err, file, fileList) {
      this.$emit('endUpload')
      this.$emit('uploadEnd')
      this.$message.error('上传失败')
    },
    handlePictureCardPreview(file) {
@@ -127,7 +127,7 @@
      this.realList.splice(tempIndex, 1)
      this.fileList.splice(tempIndex, 1)
      this.srcList.splice(tempIndex, 1)
    },
  },
}
admin/src/components/common/upload.vue
@@ -43,7 +43,7 @@
        },
        data() {
            return {
                uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/public/upload'
                uploadImgUrl: process.env.VUE_APP_API_PREFIX + '/visitsAdmin/cloudService/public/upload'
            }
        },
admin/src/views/business/visitorSources.vue
@@ -114,7 +114,7 @@
            fd.append('folder', 'visit/')
            fd.append('file', file)
            return upload(fd).then(res => {
              return res.prefixPath + res.folder + res.halfPath
              return res.url
            })
          }
        }),
admin/src/views/meeting/bookings.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,310 @@
<template>
  <TableLayout :permissions="['business:bookings:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="会议室" prop="roomId">
        <el-select
          v-model="searchForm.roomId"
          filterable
          clearable
          placeholder="请选择会议室"
        >
          <el-option v-for="item in rooms" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="预约部门" prop="department">
        <el-cascader
          v-model="searchForm.department"
          :options="department"
          :show-all-levels="false"
          clearable
          :props="props"
        ></el-cascader>
        <!-- @change="handleChange" -->
        <!-- <el-select
          v-model="searchForm.departmentId"
          filterable
          clearable
          placeholder="请选择部门"
        >
          <el-option v-for="item in department" :key="item.id" :value="item.id" :label="item.name" />
        </el-select> -->
      </el-form-item>
      <el-form-item label="会议主题" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入会议主题" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="预约人" prop="realName">
        <el-input v-model="searchForm.realName" placeholder="请输入预约人" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="会议状态" prop="status">
        <el-select
          v-model="searchForm.status"
          filterable
          clearable
          placeholder="请选择状态"
        >
          <el-option v-for="item in status" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="会议时间" prop="startTime">
        <el-date-picker
          v-model="date"
          type="datetimerange"
          range-separator="至"
          value-format="yyyy-MM-dd HH:mm:ss"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          @change="selectDate"
        ></el-date-picker>
        <!-- <el-date-picker v-model="searchForm.startTime" value-format="yyyy-MM-dd" placeholder="请输入开始时间" @change="search"/> -->
      </el-form-item>
      <!-- <el-form-item label="结束时间" prop="endTime">
        <el-date-picker v-model="searchForm.endTime" value-format="yyyy-MM-dd" placeholder="请输入结束时间" @change="search"/>
      </el-form-item> -->
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:bookings:create', 'business:bookings:exportExcel']">
        <li><el-button type="primary" @click="$refs.operaBookingsWindow.open('新建会议')" v-permissions="['business:bookings:create']">新建</el-button></li>
        <!-- <li><el-button @click="deleteByIdInBatch" v-permissions="['business:bookings:delete']">删除</el-button></li> -->
        <li><el-button :loading="isWorking.export" v-permissions="['business:bookings:exportExcel']" @click="exportExcel">导出</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <!-- <el-table-column type="selection" align="center" width="55"></el-table-column> -->
        <el-table-column prop="name" label="会议主题" align="center" min-width="120px" show-overflow-tooltip>
          <template slot-scope="{row}">
            <span class="long-title-style">{{ row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="roomName" label="会议室" align="center" min-width="120px" show-overflow-tooltip>
          <template slot-scope="{row}">
            <span class="long-title-style">{{ row.roomName }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="meetingTime" label="会议时间" align="center" min-width="120px"></el-table-column>
        <el-table-column prop="managerInfo" label="预约人" align="center" min-width="100px"></el-table-column>
        <el-table-column label="状态"  align="center" min-width="60px">
          <template slot-scope="{row}">
            <span v-if="row.status==0" style="color:rgb(127, 178, 53)">正常</span>
            <span v-else style="color:rgb(234, 54, 38)">取消</span>
            <!-- {{ row.status==0 ? '正常' : '取消' }} -->
          </template>
        </el-table-column>
        <el-table-column prop="createDate" label="创建时间" align="center" min-width="100px"></el-table-column>
        <!-- <el-table-column prop="content" label="会议内容" min-width="100px"></el-table-column> -->
        <el-table-column
          v-if="containPermissions(['business:bookings:update', 'business:bookings:delete'])"
          label="操作"
          min-width="120"
          align="center"
          fixed="right"
        >
          <template slot-scope="{row}">
            <template v-if="row.status==0">
              <el-button type="text" @click="$refs.operaBookingsDetailWindow.open('会议详情', row)">查看</el-button>
              <el-button v-if="row.flag == 0" type="text" @click="$refs.operaBookingsWindow.open('编辑会议预约', row)" v-permissions="['business:bookings:update']">修改</el-button>
              <el-button type="text" @click="copy(row)">复制</el-button>
              <el-button v-if="row.flag == 0"  type="text" @click="cancelMeeting(row.id)" v-permissions="['business:bookings:update']">取消</el-button>
            </template>
            <el-button v-else type="text" @click="deleteById(row)" v-permissions="['business:bookings:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaBookingsWindow ref="operaBookingsWindow" @success="handlePageChange"/>
    <OperaBookingsDetailWindow ref="operaBookingsDetailWindow"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaBookingsWindow from '@/views/meeting/components/OperaBookingsWindow'
import OperaBookingsDetailWindow from '@/views/meeting/components/OperaBookingsDetailWindow'
import { findList } from '@/api/meeting/rooms'
import { getSystemDictData } from '@/api/system/dictData'
import { fetchTree } from '@/api/system/department'
import { cancelById, bookingsDetail } from '@/api/meeting/bookings'
export default {
  name: 'Bookings',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaBookingsWindow, OperaBookingsDetailWindow },
  data () {
    return {
      date: [],
      // æœç´¢
      searchForm: {
        roomId: '',
        // departmentId: [],
        department: [],
        realName: '',
        status: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        name: '',
        roomId: '',
        startTime: '',
        endTime: '',
        content: ''
      },
      props: {
        label: 'name',
        value: 'id',
        checkStrictly: true
      },
      rooms: [
        { name: '201会议室', id: '0' }
      ],
      department: [
        { name: '开发部门', id: '0' }
      ],
      status: [
        { name: '全部', id: '' },
        { name: '正常', id: '0' },
        { name: '取消', id: '1' },
      ],
      link: 'https://dmtest.ahapp.net/meeting_h5/' //H5_LINK_ADDR
    }
  },
  provide() {
    return {
      rooms: () => this.rooms
    }
  },
  created () {
    this.config({
      module: '会议室预定信息表',
      api: '/meeting/bookings',
      'field.id': 'id',
      'field.main': 'id'
    })
    fetchTree()
      .then(res => {
        this.department = this.newTree(res)
      })
    getSystemDictData('H5_LINK_ADDR')
      .then(res => {
        console.log(res);
        this.link=res.code
      })
    findList({status:0})
      .then(res => {
        this.rooms = res
      })
    this.search()
  },
  methods: {
    newTree(tree) {
      return tree.map(item => {
        let newItem = {...item}
        if (item.children.length == 0) {
          this.$delete( newItem, 'children' )
        } else {
          newItem.children = this.newTree(newItem.children)
        }
        return newItem
      });
    },
    selectDate(v) {
      this.searchForm.endTime = v[1] + ' 23:59:59'
      this.searchForm.startTime = v[0] + ' 00:00:00'
    },
    reset () {
      this.$refs.searchForm.resetFields()
      this.date = []
      this.searchForm.startTime = ''
      this.searchForm.endTime = ''
      this.search()
    },
    copy(row) {
      let text = `${row.realName} é‚€è¯·æ‚¨åŠ å…¥ä¼šè®®\n会议主题:${row.name}\n会议室:${row.roomName}\n会议时间:${row.meetingTime}\n点击链接直接加入会议:\n${this.link}?id=${row.id}`
      this.$copyText(text)
        .then(() => {
          this.$message.success('会议信息复制成功,去分享给同事吧~')
        })
        .catch(e => {
          this.$message.error(e)
        })
    },
    cancelMeeting(id) {
      this.$dialog.messageWaring('取消会议', '是否取消当前会议?')
        .then(() => {
          cancelById({id})
            .then(() => {
              this.$message.success('取消成功')
              this.handlePageChange()
            })
            .catch(e => {
              this.$message.error(e)
            })
        })
    },
    showDetail(id) {
      bookingsDetail(id)
        .then(res => {
          this.$refs.operaBookingsDetailWindow.open('会议详情', res)
        })
        .catch(e => {
          this.$message.error(e)
        })
    },
    editBookings(id) {
      bookingsDetail(id)
        .then(res => {
          this.$refs.operaBookingsWindow.open('编辑会议预约', res)
        })
        .catch(e => {
          this.$message.error(e)
        })
    },
    handlePageChange (pageIndex) {
      this.__checkApi()
      this.tableData.pagination.pageIndex = pageIndex || this.tableData.pagination.pageIndex
      this.isWorking.search = true
      let form = JSON.parse(JSON.stringify(this.searchForm))
      if (form.department.length) {
        form.departmentId = form.department[form.department.length-1]
      }
      this.api.fetchList({
        page: this.tableData.pagination.pageIndex,
        capacity: this.tableData.pagination.pageSize,
        model: form,
        sorts: this.tableData.sorts
      })
        .then(data => {
          this.tableData.list = data.records
          this.tableData.pagination.total = data.total
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking.search = false
        })
    },
  },
}
</script>
admin/src/views/meeting/components/OperaBookingsDetailWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,164 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
    width="600px"
  >
    <div class="title-style">
      <div class="header-title">{{ form.name }}</div>
      <div class="item-value">{{ `${form.roomName} ${form.meetingTime}` }}</div>
    </div>
    <div class="content-style">
      <div class="item">
        <div class="item-title">参会人员</div>
        <div>{{ form.sysList.map(item => `${item.realName}`).join(',') }}</div>
      </div>
      <div class="item">
        <div class="item-title">会议内容</div>
        <div class="item-value">{{ form.content || '无' }}</div>
      </div>
      <div v-if="form.projectList.length" class="item">
        <div class="">服务项</div>
        <div class="item-value">{{ form.projectList.map(item => item.projectName).join(' | ') }}</div>
      </div>
      <div class="item" v-if="form.fileList.length">
        <div class="item-title">附件</div>
        <div>
          <FileLink
            :links="form.fileList"
            linkName="fileFullUrl"
            :isUpload="false"
          />
        </div>
      </div>
      <div class="item" v-if="!!form.remark">
        <div class="item-title">备注</div>
        <div class="item-value">{{ form.remark }}</div>
      </div>
    </div>
    <div class="bottom-style">
      <div class="item-title">预约人</div>
      <div class="item-value">{{ form.managerInfo }}</div>
    </div>
    <div slot="footer">
      <el-button @click="visible=false">取消</el-button>
    </div>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import FileLink from '@/views/meeting/components/common/FileLink'
export default {
  name: 'OperaBookingsDetailWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow, FileLink },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        roomName: '',
        meetingTime: '',
        date: '',
        editDate: '',
        projectList: [],
        remark: '',
        roomId: '',
        startTime: '',
        endTime: '',
        times: [],
        content: '',
        sysList: [],
        fileList: [],
        managerInfo: ''
      },
      // room: [],
      sysList: [],
      projectList: [],
      timelist: [],
      // éªŒè¯è§„则
      rules: {
      }
    }
  },
  created () {
    this.config({
      api: '/meeting/bookings',
      'field.id': 'id'
    })
  },
  methods: {
    /**
     * æ‰“开窗口
     * @title çª—口标题
     * @target ç¼–辑的对象
     */
    //  open (title, target) {
    //   this.title = title
    //   this.visible = true
    //   this.timelist = []
    //   // æ–°å»º
    //   if (target == null) {
    //     this.$nextTick(() => {
    //       this.$refs.form.resetFields()
    //       this.form[this.configData['field.id']] = null
    //     })
    //     return
    //   }
    //   // ç¼–辑
    //   this.$nextTick(() => {
    //     for (const key in this.form) {
    //       this.form[key] = target[key]
    //     }
    //     // this.form.projectList = target.projectList ? target.projectList.map(item => item.projectId) : []
    //     // this.form.sysList = this.form.sysList ? this.form.sysList.map(item => item.userId) : []
    //     // this.form.date = target.startTime.split(' ')[0]
    //   })
    // },
  },
}
</script>
<style lang="scss" scoped>
::v-deep .el-dialog__body {
  padding: 0;
}
.title-style {
  padding: 20px;
  border-bottom: 10px #f7f7f7 solid;
}
.content-style {
  padding: 20px;
  border-bottom: 10px #f7f7f7 solid;
}
.item {
  padding: 5px 0;
}
.header-title {
  font-size: 16px;
  font-weight: 600;
  padding-bottom: 5px;
}
.item-title {
  font-size: 16px;
  color: #999;
  padding-bottom: 5px;
}
.item-value {
  font-size: 14px;
  color: #111;
}
.bottom-style {
  padding: 20px;
}
</style>
admin/src/views/meeting/components/OperaBookingsWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,442 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" :rules="rules" label-width="120px" label-suffix=":">
      <el-form-item label="关联会议室" prop="roomId">
        <el-select
          v-model="form.roomId"
          filterable
          clearable
          placeholder="请选择关联会议室"
          @change="selectRoom"
        >
          <el-option v-for="item in rooms()" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="预定日期" prop="date">
        <el-date-picker
          v-model="form.date"
          value-format="yyyy-MM-dd"
          placeholder="请选择预定日期"
          @change="selectDate"
        ></el-date-picker>
      </el-form-item>
      <el-form-item label="预定时间" prop="times">
        <div class="time-style">
          <div
            class="time-item"
            v-for="(item, index) in timelist"
            :key="item.id"
            :class="form.times.indexOf(index)!=-1?'time-item-sel': item.isUse ? 'time-item-disable' : ''"
            @click="selectTimes(index, item)"
          >{{ `${item.startTime}-${item.endTime}` }}</div>
        </div>
      </el-form-item>
      <el-form-item label="会议主题" prop="name">
        <el-input v-model="form.name" placeholder="请输入会议主题" :maxlength="30" v-trim/>
      </el-form-item>
      <el-form-item label="参会人员" prop="sysList">
        <!-- <el-input style="width:40%" disabled v-model="sysList" placeholder="选择参会人员" v-trim/> -->
        <el-select
          v-model="form.sysList"
          filterable
          clearable
          multiple
          placeholder="选择部门成员"
        >
          <el-option
            v-for="item in sysList"
            :key="item.id"
            :value="item.id"
            :label="item.department?`${item.department.name}-${item.realname}`:item.realname"
          ></el-option>
          <!-- <el-option :key="1" :value="1" label="禁用" /> -->
        </el-select>
      </el-form-item>
      <el-form-item label="会议内容" prop="content">
        <el-input
          type="textarea"
          v-model="form.content"
          :maxlength="300"
          show-word-limit
          :autosize="{ minRows: 4, maxRows: 12}"
          placeholder="请输入会议内容"
          v-trim
        />
      </el-form-item>
      <el-form-item v-if="projectList.length" label="选择服务项目" prop="projectList">
        <el-checkbox-group v-model="form.projectList">
          <el-checkbox
            v-for="project in projectList"
            :label="project.id"
            :key="project.id"
          >{{project.name}}</el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="会议附件" prop="fileList">
        <div>
          <el-button type="primary" icon="el-icon-upload" @click="$refs.upFile.click()">会议附件</el-button>
        </div>
        <div class="data-list">
          <FileLink
            :links="form.fileList"
            linkName="fileFullUrl"
          />
        </div>
      </el-form-item>
      <el-form-item label="会议备注" prop="remark">
        <el-input type="textarea" v-model="form.remark" placeholder="请输入会议备注" v-trim/>
      </el-form-item>
      <input type="file" @change="upFiles" ref="upFile" style="display: none;" />
    </el-form>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import FileLink from '@/views/meeting/components/common/FileLink'
import { uploadFileLocal as upload } from '@/api/system/common'
import { fetchList as userList } from '@/api/system/user'
import { findListByObjId } from '@/api/meeting/projects'
import { findList } from '@/api/meeting/roomTime'
import { numRule, arrayRule } from '@/utils/form'
export default {
  name: 'OperaBookingsWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow, FileLink },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        date: '',
        editDate: '',
        projectList: [],
        remark: '',
        name: '',
        roomId: '',
        startTime: '',
        endTime: '',
        times: [],
        content: '',
        sysList: [],
        fileList: [],
      },
      isEdit: false,
      // room: [],
      sysList: [],
      projectList: [],
      timelist: [],
      // éªŒè¯è§„则
      rules: {
        roomId: [
         { required: true, validator: numRule, message: '请选择关联会议室', tigger: 'change' }
        ],
        date: [
         { required: true, message: '请选择预定日期', tigger: 'change' }
        ],
        times: [
         { required: true, validator: arrayRule, message: '请选择预约时间', tigger: 'change' }
        ],
        sysList: [
         { required: true, validator: arrayRule, message: '请选择参会人员', tigger: 'change' }
        ],
        name: [
         { required: true, message: '请选择输入会议主题', tigger: 'blur' }
        ],
        // content: [
        //  { required: true, message: '请输入会议内容', tigger: 'blur' }
        // ],
      }
    }
  },
  inject: ['rooms'],
  created () {
    this.config({
      api: '/meeting/bookings',
      'field.id': 'id'
    })
    userList({
      page: 1,
      capacity: 9999,
      model: { realname: this.filterText },
    })
      .then(res => {
        console.log('userList', res);
        this.sysList = res.records
      })
  },
  methods: {
    /**
     * æ‰“开窗口
     * @title çª—口标题
     * @target ç¼–辑的对象
     */
     open (title, target) {
      this.title = title
      this.visible = true
      this.timelist = []
      this.isEdit = false
      // æ–°å»º
      if (target == null) {
        this.$nextTick(() => {
          this.$refs.form.resetFields()
          console.log(this.form.content);
          debugger
          this.form[this.configData['field.id']] = null
        })
        return
      }
      // ç¼–辑
      this.$nextTick(() => {
        for (const key in this.form) {
          this.form[key] = target[key]
        }
        this.isEdit = true
        this.form.projectList = target.projectList ? target.projectList.map(item => item.projectId) : []
        this.form.sysList = this.form.sysList ? this.form.sysList.map(item => item.userId) : []
        // console.log(target.startTime.split(' '));
        // debugger
        this.form.date = target.startTime.split(' ')[0]
        this.getTimes(true)
        this.selectRoom(this.form.roomId)
      })
    },
    selectRoom(objId) {
      this.getTimes()
      findListByObjId({
        objId,
        objType: 0,
      })
        .then(res => {
          this.projectList = res
        })
    },
    selectDate(v) {
      // console.log(v);
      this.getTimes()
    },
    getTimes(isInit=false) {
      this.form.times = []
      this.timelist = []
      if (this.form.date && this.form.roomId) {
        findList({
          yudingDate: this.form.date + ' 00:00:00',
          roomId: this.form.roomId,
          bookingId: this.form.id
        })
          .then(res => {
            this.timelist = res
            if (isInit) {
              this.timelist.forEach((itme, index) => {
                if (itme.isChoose) {
                  itme.isUse = false
                  this.form.times.push(index)
                }
              })
              // let startTime = this.form.startTime.split(' ')[1]
              // let endTime = this.form.endTime.split(' ')[1]
              // let firstIndex = this.timelist.findIndex(item => item.startTime == startTime)
              // let lastIndex = this.timelist.findIndex(item => item.endTime == endTime)
              // let index = firstIndex
              // while(index <= lastIndex) {
              //   this.form.times.push(index)
              //   index ++
              // }
              // console.log('startTime', startTime);
              // console.log('endTime', endTime);
              // console.log('firstIndex', firstIndex);
              // console.log('lastIndex', lastIndex);
              // console.log('this.form.times', this.form.times);
            }
          })
      }
    },
    selectTimes(index, item) {
      if (this.isEdit) {
        return
      }
      let tempIndex = this.form.times.indexOf(index)
      if (tempIndex != -1) {
        if (tempIndex==0) {
          // console.log(this.form.times);
          // debugger
          this.form.times.splice(0, 1)
        } else if (tempIndex==this.form.times.length-1) {
          this.form.times.splice(tempIndex, 1)
        }
      } else {
        if (item.isUse) {
          return
        }
        if (this.form.times.length && index+1 !== this.form.times[0] && index-1 !== this.form.times[this.form.times.length-1]) {
          this.$message.error('预约时间必须是相邻的!')
          return
        }
        this.form.times.push(index)
        this.form.times.sort((x,y)=> x - y)
      }
      // console.log(this.form.times);
    },
    upFiles(file) {
      const formdate = new FormData()
      this.isUploading = true
      formdate.append('file', file.target.files[0])
      formdate.append('folder', 'projects')
      upload(formdate)
        .then(res => {
          // console.log(this.form);
          this.form.fileList.push({
            name: res.originname,
            url: res.url,
            fileurl: res.imgaddr
          })
        })
        .catch(err => {
          console.log(err)
        })
        .finally(() => this.isUploading = false)
      this.$refs.upFile.value = null
    },
    // ç¡®è®¤æ–°å»º
    __confirmCreate () {
      this.$refs.form.validate((valid) => {
        // debugger
        if (!valid) {
          return
        }
        // console.log(this.form);
        // debugger
        // è°ƒç”¨æ–°å»ºæŽ¥å£
        this.isWorking = true
        let sysList = [...this.form.sysList]
        sysList = sysList.map(item => {
          return {userId: item}
        })
        let projectList = [...this.form.projectList]
        projectList = projectList.map(item => {
          return {projectId: item}
        })
        let bookingTimeList = []
        this.form.times.forEach(item => {
          bookingTimeList.push({
            timeId: this.timelist[item].id,
            id: this.timelist[item].bookingTimeId
          })
        })
        let startTime = this.form.date + ' ' + this.timelist[this.form.times[0]].startTime + ':00'
        let endTime = this.form.date + ' ' + this.timelist[this.form.times[this.form.times.length-1]].endTime + ':00'
        this.api.create({
          ...this.form,
          sysList,
          projectList,
          startTime,
          endTime,
          bookingTimeList
        })
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('新建成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    },
    // ç¡®è®¤ä¿®æ”¹
    __confirmEdit () {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        // è°ƒç”¨æ–°å»ºæŽ¥å£
        this.isWorking = true
        let sysList = [...this.form.sysList]
        sysList = sysList.map(item => {
          return {userId: item}
        })
        let projectList = [...this.form.projectList]
        projectList = projectList.map(item => {
          return {projectId: item}
        })
        let bookingTimeList = []
        this.form.times.forEach(item => {
          bookingTimeList.push({
            timeId: this.timelist[item].id,
            id: this.timelist[item].bookingTimeId
          })
        })
        let startTime = this.form.date + ' ' + this.timelist[this.form.times[0]].startTime + ':00'
        let endTime = this.form.date + ' ' + this.timelist[this.form.times[this.form.times.length-1]].endTime + ':00'
        this.api.updateById({
          ...this.form,
          sysList,
          projectList,
          startTime,
          endTime,
          bookingTimeList
        })
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('修改成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    }
  },
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
@import "@/assets/style/variables.scss";
::v-deep .el-input.is-disabled .el-input__inner {
  background-color: #fff !important;
  cursor: pointer;
}
.time-style {
  display: flex;
  flex-wrap: wrap;
  cursor: pointer;
  .time-item {
    margin-right: 8px;
    margin-bottom: 8px;
    border: #111 solid 1px;
    font-size: 14px;
    line-height: 14px;
    padding: 5px;
    border-radius: 5px;
    color: #111;
  }
  .time-item-sel {
    border-color: $primary-color;
    background-color: $primary-color;
    color: #fff;
  }
  .time-item-disable {
    border-color: #999;
    background-color: #999;
    color: #111;
  }
}
</style>
admin/src/views/meeting/components/OperaDevicesWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" label-width="110px" label-suffix=":" :rules="rules">
      <!-- <el-form-item label="创建人编码" prop="creator">
        <el-input v-model="form.creator" placeholder="请输入创建人编码" v-trim/>
      </el-form-item>
      <el-form-item label="创建时间" prop="createDate">
        <el-date-picker v-model="form.createDate" value-format="yyyy-MM-dd" placeholder="请输入创建时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="更新人编码" prop="editor">
        <el-input v-model="form.editor" placeholder="请输入更新人编码" v-trim/>
      </el-form-item>
      <el-form-item label="更新时间" prop="editDate">
        <el-date-picker v-model="form.editDate" value-format="yyyy-MM-dd" placeholder="请输入更新时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="是否删除0否 1是" prop="isdeleted">
        <el-input v-model="form.isdeleted" placeholder="请输入是否删除0否 1是" v-trim/>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" placeholder="请输入备注" v-trim/>
      </el-form-item> -->
      <el-form-item label="门禁ID" prop="code">
        <el-input v-model="form.code" placeholder="请输入门禁ID" v-trim/>
      </el-form-item>
      <el-form-item label="门禁名称" prop="name">
        <el-input v-model="form.name" placeholder="请输入门禁名称" v-trim/>
      </el-form-item>
      <el-form-item label="关联会议室" prop="roomId">
        <el-select
          v-model="form.roomId"
          filterable
          clearable
          placeholder="请选择关联会议室"
        >
          <el-option v-for="item in room()" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <!-- <el-form-item label="状态 0启用 1禁用" prop="status">
        <el-input v-model="form.status" placeholder="请输入状态 0启用 1禁用" v-trim/>
      </el-form-item> -->
    </el-form>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import { numRule } from '@/utils/form'
export default {
  name: 'OperaDevicesWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        name: '',
        code: '',
        roomId: '',
      },
      // éªŒè¯è§„则
      rules: {
        code: [
         { required: true, message: '请输入门禁ID', tigger: 'blur' }
        ],
        name: [
         { required: true, message: '请输入门禁名称', tigger: 'blur' }
        ],
        roomId: [
         { required: true, validator: numRule, message: '请选择关联会议室', tigger: 'change' }
        ],
      }
    }
  },
  inject: ['room'],
  created () {
    this.config({
      api: '/meeting/devices',
      'field.id': 'id'
    })
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
</style>
admin/src/views/meeting/components/OperaNoticeWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    width="70%"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" :rules="rules">
      <el-form-item label="标题" prop="title">
        <el-input v-model="form.title" placeholder="请输入标题,不超过30个字" maxlength="30" v-trim/>
      </el-form-item>
      <el-form-item label="内容" prop="content">
        <!-- <el-input type="textarea" v-model="form.content" placeholder="请输入内容" v-trim/> -->
      </el-form-item>
      <RichEditor :content="{ content: form.content }" @edit="form.content=$event"></RichEditor>
      <!-- <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" placeholder="请输入备注" v-trim/>
      </el-form-item>
      <el-form-item label="用户编码(关联member表)" prop="memberId">
        <el-input v-model="form.memberId" placeholder="请输入用户编码(关联member表)" v-trim/>
      </el-form-item>
      <el-form-item label="对象编码" prop="objId">
        <el-input v-model="form.objId" placeholder="请输入对象编码" v-trim/>
      </el-form-item>
      <el-form-item label="对象类型 " prop="objType">
        <el-input v-model="form.objType" placeholder="请输入对象类型 " v-trim/>
      </el-form-item>
      <el-form-item label="消息类型 0系统消息 1会议通知" prop="type">
        <el-input v-model="form.type" placeholder="请输入消息类型 0系统消息 1会议通知" v-trim/>
      </el-form-item>
      <el-form-item label="状态 0未读 1已读" prop="status">
        <el-input v-model="form.status" placeholder="请输入状态 0未读 1已读" v-trim/>
      </el-form-item> -->
    </el-form>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import RichEditor from '@/components/common/RichEditor.vue'
export default {
  name: 'OperaNoticeWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow, RichEditor },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        memberId: '',
        title: '',
        content: '',
        objId: '',
        objType: '',
        type: '',
        status: ''
      },
      // éªŒè¯è§„则
      rules: {
      }
    }
  },
  created () {
    this.config({
      api: 'meeting/notice',
      'field.id': 'id'
    })
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
</style>
admin/src/views/meeting/components/OperaProjectsWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,134 @@
<template>
  <GlobalAlertWindow
    v-loading="isUploading"
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" :rules="rules" label-width="120px" label-suffix=":">
      <el-form-item label="名称" prop="name">
        <el-input v-model="form.name" maxlength="6" placeholder="请输入,不超过6个字" v-trim/>
      </el-form-item>
      <el-form-item label="展示图" prop="imgurlfull">
        <!-- {{ form.imgurlfull }} -->
        <UploadAvatarImage
          :file="{ 'imgurlfull': form.imgurlfull, 'imgurl': form.imgurl }"
          :uploadData="uploadData"
          @uploadSuccess="uploadAvatarSuccess"
          @uploadEnd="isUploading = false"
          @uploadBegin="isUploading = true"
        />
      </el-form-item>
      <el-form-item label="排序码(升序)" prop="sortnum">
        <el-input v-model="form.sortnum" placeholder="请输入排序码" v-trim/>
      </el-form-item>
      <!-- <el-form-item label="创建人编码" prop="creator">
        <el-input v-model="form.creator" placeholder="请输入创建人编码" v-trim/>
      </el-form-item>
      <el-form-item label="创建时间" prop="createDate">
        <el-date-picker v-model="form.createDate" value-format="yyyy-MM-dd" placeholder="请输入创建时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="更新人编码" prop="editor">
        <el-input v-model="form.editor" placeholder="请输入更新人编码" v-trim/>
      </el-form-item>
      <el-form-item label="更新时间" prop="editDate">
        <el-date-picker v-model="form.editDate" value-format="yyyy-MM-dd" placeholder="请输入更新时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="是否删除0否 1是" prop="isdeleted">
        <el-input v-model="form.isdeleted" placeholder="请输入是否删除0否 1是" v-trim/>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" placeholder="请输入备注" v-trim/>
      </el-form-item>
      <el-form-item label="图标" prop="imgurl">
        <el-input v-model="form.imgurl" placeholder="请输入图标" v-trim/>
      </el-form-item>
      <el-form-item label="状态 0启用 1禁用" prop="status">
        <el-input v-model="form.status" placeholder="请输入状态 0启用 1禁用" v-trim/>
      </el-form-item> -->
    </el-form>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import UploadAvatarImage from '@/components/common/UploadAvatarImage'
export default {
  name: 'OperaProjectsWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow, UploadAvatarImage },
  data () {
    return {
      isUploading: false,
      uploadData: {
        folder: 'projects'
      },
      // è¡¨å•数据
      form: {
        id: null,
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        name: '',
        remark: '',
        imgurlfull: '',
        imgurl: '',
        status: '',
        sortnum: ''
      },
      // éªŒè¯è§„则
      rules: {
      }
    }
  },
  created () {
    this.config({
      api: '/meeting/projects',
      'field.id': 'id'
    })
  },
  methods: {
    /**
     * æ‰“开窗口
     * @title çª—口标题
     * @target ç¼–辑的对象
     */
     open (title, target) {
      this.title = title
      this.visible = true
      this.form.imgurl = ''
      this.form.imgurlfull = ''
      debugger
      // æ–°å»º
      if (target == null) {
        this.$nextTick(() => {
          this.$refs.form.resetFields()
          this.form[this.configData['field.id']] = null
        })
        return
      }
      // ç¼–辑
      this.$nextTick(() => {
        for (const key in this.form) {
          this.form[key] = target[key]
        }
        console.log('this.form', this.form);
      })
    },
    // ä¸Šä¼ å›¾ç‰‡
    uploadAvatarSuccess(file) {
      this.form.imgurl = file.imgurl;
      this.form.imgurlfull = file.imgurlfull;
    },
  }
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
</style>
admin/src/views/meeting/components/OperaRoomRecordWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,78 @@
<template>
  <GlobalWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" :rules="rules">
      <el-form-item label="创建人编码" prop="creator">
        <el-input v-model="form.creator" placeholder="请输入创建人编码" v-trim/>
      </el-form-item>
      <el-form-item label="创建时间" prop="createDate">
        <el-date-picker v-model="form.createDate" value-format="yyyy-MM-dd" placeholder="请输入创建时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="更新人编码" prop="editor">
        <el-input v-model="form.editor" placeholder="请输入更新人编码" v-trim/>
      </el-form-item>
      <el-form-item label="更新时间" prop="editDate">
        <el-date-picker v-model="form.editDate" value-format="yyyy-MM-dd" placeholder="请输入更新时间"></el-date-picker>
      </el-form-item>
      <el-form-item label="是否删除0否 1是" prop="isdeleted">
        <el-input v-model="form.isdeleted" placeholder="请输入是否删除0否 1是" v-trim/>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="form.remark" placeholder="请输入备注" v-trim/>
      </el-form-item>
      <el-form-item label="人员编码(关联system_user表)" prop="userId">
        <el-input v-model="form.userId" placeholder="请输入人员编码(关联system_user表)" v-trim/>
      </el-form-item>
      <el-form-item label="关联对象编码(关联rooms或booking表)" prop="objId">
        <el-input v-model="form.objId" placeholder="请输入关联对象编码(关联rooms或booking表)" v-trim/>
      </el-form-item>
      <el-form-item label="关联对象类型 0会议室管理员 1参会人员" prop="objType">
        <el-input v-model="form.objType" placeholder="请输入关联对象类型 0会议室管理员 1参会人员" v-trim/>
      </el-form-item>
      <el-form-item label="会议室编码(关联rooms表)" prop="roomId">
        <el-input v-model="form.roomId" placeholder="请输入会议室编码(关联rooms表)" v-trim/>
      </el-form-item>
    </el-form>
  </GlobalWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  name: 'OperaRoomRecordWindow',
  extends: BaseOpera,
  components: { GlobalWindow },
  data () {
    return {
      // è¡¨å•数据
      form: {
        id: null,
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        userId: '',
        objId: '',
        objType: '',
        roomId: ''
      },
      // éªŒè¯è§„则
      rules: {
      }
    }
  },
  created () {
    this.config({
      api: '/meeting/roomRecord',
      'field.id': 'id'
    })
  }
}
</script>
admin/src/views/meeting/components/OperaRoomsWindow.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,275 @@
<template>
  <GlobalAlertWindow
    v-loading="isUploading"
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <el-form :model="form" ref="form" :rules="rules" label-width="120px" label-suffix=":">
      <el-form-item label="会议室名称" prop="name">
        <el-input v-model="form.name" placeholder="请输入会议室名称" :maxlength="10" v-trim/>
      </el-form-item>
      <el-form-item label="开放时间" prop="timeRange">
        <el-time-picker
          is-range
          value-format="HH:mm"
          format="HH:mm"
          v-model="timeRange"
          range-separator="至"
          start-placeholder="开始时间"
          end-placeholder="结束时间"
          placeholder="选择时间范围"
          @change="selectRange"
        ></el-time-picker>
      </el-form-item>
      <el-form-item label="粒度分钟" prop="intervalTime">
        <el-input v-model="form.intervalTime" type="number" placeholder="请输入时间粒度(分钟)" v-trim/>
      </el-form-item>
      <el-form-item label="容纳人数" prop="limitNum">
        <el-input v-model="form.limitNum" type="number" placeholder="请输入容纳人数" v-trim/>
      </el-form-item>
      <el-form-item label="管理员" prop="sysList">
        <el-select
          v-model="form.sysList"
          filterable
          multiple
          clearable
          placeholder="请选择部门"
        >
        <!-- :label="`${item.department.name}-${item.realname}`" -->
          <el-option
            v-for="item in userList()"
            :key="item.id"
            :value="item.id"
            :label="item.department?`${item.department.name}-${item.realname}`:item.realname"
          />
        </el-select>
      </el-form-item>
      <el-form-item label="提供服务项目" prop="projectList">
        <el-checkbox-group v-model="form.projectList">
          <el-checkbox v-for="project in projectList" :label="project.id" :key="project.id">{{project.name}}</el-checkbox>
        </el-checkbox-group>
      </el-form-item>
      <el-form-item label="会议室图片" prop="imgurl">
        <UploadAvatarImage
          :file="{ 'imgurlfull': form.imgFullUrl, 'imgurl': form.imgurl }"
          :uploadData="uploadData"
          @uploadSuccess="uploadAvatarSuccess"
          @uploadEnd="isUploading = false"
          @uploadBegin="isUploading = true"
        />
      </el-form-item>
      <el-form-item label="使用须知" prop="tips">
        <el-input v-model="form.tips" type="textarea" placeholder="请输入使用须知" v-trim/>
      </el-form-item>
    </el-form>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import UploadAvatarImage from '@/components/common/UploadAvatarImage'
import { numRule } from '@/utils/form'
import { fetchList } from '@/api/meeting/projects'
export default {
  name: 'OperaRoomsWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow, UploadAvatarImage },
  data () {
    let timeRangeRule = (rule, value, callBack) => {
      if (!this.form.startTime) {
        callBack(new Error('请选择开始时间'))
        return
      }
      if (!this.form.endTime) {
        callBack(new Error('请选择结束时间'))
        return
      }
      callBack()
    }
    return {
      isUploading: false,
      uploadData: {
        folder: 'projects'
      },
      timeRange: ['', ''],
      // è¡¨å•数据
      form: {
        id: null,
        sysList: [],
        projectList: [],
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        name: '',
        remark: '',
        startTime: '',
        endTime: '',
        limitNum: '',
        imgurl: '',
        imgFullUrl: '',
        tips: '',
        status: '',
        intervalTime: ''
      },
      user: [],
      projectList: [],
      // éªŒè¯è§„则
      rules: {
        name: [
          { required: true, message: '请输入会议室名称', tigger: 'blur' }
        ],
        intervalTime: [
          { required: true, validator: numRule, message: '请输入时间粒度', tigger: 'blur' }
        ],
        timeRange: [
          { required: true, validator: timeRangeRule, tigger: 'change' }
        ]
      }
    }
  },
  inject: ['userList'],
  created () {
    this.config({
      api: '/meeting/rooms',
      'field.id': 'id'
    })
    // realname: this.filterText
    fetchList({
      page: 1,
      capacity: 9999,
      model: {},
    })
      .then(res => {
        this.projectList = res.records
      })
  },
  methods: {
    /**
     * æ‰“开窗口
     * @title çª—口标题
     * @target ç¼–辑的对象
     */
     open (title, target) {
      this.title = title
      this.visible = true
      this.form.imgFullUrl = ''
      // this.timeRange = ['14:34:55', '14:34:55']
      // debugger
      this.timeRange = ['', '']
      // æ–°å»º
      if (target == null) {
        this.$nextTick(() => {
          this.$refs.form.resetFields()
          this.form[this.configData['field.id']] = null
        })
        return
      }
      // ç¼–辑
      this.$nextTick(() => {
        for (const key in this.form) {
          this.form[key] = target[key]
        }
        this.timeRange = [target.startTime, target.endTime]
        this.form.projectList = this.form.projectList ? target.projectList.map(item => item.projectId) : []
        this.form.sysList = this.form.sysList ? this.form.sysList.map(item => item.userId) : []
        // console.log(this.form.imgFullUrl);
      })
    },
    selectRange(v) {
      // console.log(this.timeRange);
      console.log(v);
      this.form.startTime = v[0]
      this.form.endTime = v[1]
      console.log(this.form.startTime, this.form.endTime);
    },
    // ä¸Šä¼ å›¾ç‰‡
    uploadAvatarSuccess(file) {
      this.form.imgurl = file.imgurl;
      this.form.imgFullUrl = file.imgurlfull;
    },
    // ç¡®è®¤æ–°å»º
    __confirmCreate () {
      this.$refs.form.validate((valid) => {
        // debugger
        if (!valid) {
          return
        }
        // console.log(this.form);
        // debugger
        // è°ƒç”¨æ–°å»ºæŽ¥å£
        this.isWorking = true
        let sysList = [...this.form.sysList]
        sysList = sysList.map(item => {
          return {userId: item}
        })
        let projectList = [...this.form.projectList]
        projectList = projectList.map(item => {
          return {projectId: item}
        })
        this.api.create({
          ...this.form,
          sysList,
          projectList
        })
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('新建成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    },
    // ç¡®è®¤ä¿®æ”¹
    __confirmEdit () {
      this.$refs.form.validate((valid) => {
        if (!valid) {
          return
        }
        console.log(this.form);
        debugger
        // è°ƒç”¨æ–°å»ºæŽ¥å£
        this.isWorking = true
        let sysList = [...this.form.sysList]
        sysList = sysList.map(item => {
          return {userId: item}
        })
        let projectList = [...this.form.projectList]
        projectList = projectList.map(item => {
          return {projectId: item}
        })
        this.api.updateById({
          ...this.form,
          sysList,
          projectList
        })
          .then(() => {
            this.visible = false
            this.$tip.apiSuccess('修改成功')
            this.$emit('success')
          })
          .catch(e => {
            this.$tip.apiFailed(e)
          })
          .finally(() => {
            this.isWorking = false
          })
      })
    }
  },
}
</script>
<style lang="scss" scoped>
@import "@/assets/style/alertstyle.scss";
</style>
admin/src/views/meeting/components/common/FileLink.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,92 @@
<template>
  <div>
    <FileLinkItem
      v-for="(item, index) in links"
      :key="index"
      :link="item[linkName]"
      :name="item.name"
      :isUpload="isUpload"
      @showFile="showFile"
      @deleteAction="deleteFile(index)"
    />
    <PDFPreview ref="PDFPreview" />
    <el-image-viewer
      v-if="showViewer"
      :on-close="close"
      :initialIndex="tempIndex"
      :url-list="srcList"
      :zIndex="3000"
    />
  </div>
</template>
<script>
import { fileType } from '@/utils/util';
import FileLinkItem from './FileLinkItem.vue';
import PDFPreview from './PDFPreview'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
export default {
  components: {
    FileLinkItem,
    PDFPreview,
    ElImageViewer
  },
  props: {
    links: {
      type: Array,
      required: true
    },
    isUpload: {
      type: Boolean,
      default: true
    },
    linkName: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      showViewer: false
    }
  },
  computed: {
    // å›¾ç‰‡åœ°å€
    srcList() {
      return this.links.filter(item => {
        let link = item[this.linkName]
        return fileType(link) == 1
      }).map(item => item[this.linkName])
    }
  },
  methods: {
    deleteFile(index) {
      this.links.splice(index, 1)
    },
    downloadFile(url) {
      window.open(url, '_blank')
    },
    showFile(url) {
      debugger
      let type = fileType(url)
      switch (type) {
        case 1:
          this.tempIndex = this.srcList.findIndex(item => item == url)
          this.showViewer = true
          break;
        case 2:
          this.$refs.PDFPreview.open('', { url })
          break;
        case 3:
          window.open(url, '_blank')
          break;
        default:
          break;
      }
    },
    close() {
      this.showViewer = false
    }
  },
}
</script>
admin/src/views/meeting/components/common/FileLinkItem.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,89 @@
<template>
  <div class="file-link">
    <div class="like-link" @click="showFile(link)">{{ name }}</div>
    <i v-if="isUpload" class="el-icon-delete delete" @click="deleteFile()"></i>
    <i v-else class="el-icon-download download" @click="downloadFile(link)"></i>
  </div>
</template>
<script>
export default {
  props: {
    link: {
      type: String,
      default: ''
    },
    name: {
      type: String,
      default: ''
    },
    isUpload: {
      type: Boolean,
      default: true
    }
  },
  data() {
    return {
      showViewer: false
    }
  },
  methods: {
    deleteFile() {
      this.$emit('deleteAction')
    },
    downloadFile(url) {
      window.open(url, '_blank')
    },
    showFile(link) {
      this.$emit('showFile',link)
    }
  },
}
</script>
<style lang="scss" scoped>
.file-link {
  // height: 26px;
  display: flex;
  font-size: 14px;
  line-height: 26px;
  .like-link {
    line-height: 26px;
    color: #216EEE;
    cursor: pointer;
    text-decoration: underline;
  }
  .delete {
    box-sizing: border-box;
    line-height: 26px;
    margin-left: 10px;
    width: 16px;
    height: 16px;
    // background-color: #BFC3CB;
    color: #216EEE;
    border-radius: 50%;
    padding: 1.5px;
    cursor: pointer;
    &:hover {
      color: #ff0000;
    }
  }
  .download {
    line-height: 26px;
    box-sizing: border-box;
    margin-left: 10px;
    width: 16px;
    height: 16px;
    color: #828D9E;
    border-radius: 50%;
    padding: 1.5px;
    cursor: pointer;
    &:hover {
      color: #216EEE;
    }
  }
}
</style>
admin/src/views/meeting/components/common/PDFPreview.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,95 @@
<template>
   <el-dialog
    class="global-window"
    :visible="visible"
    :with-header="true"
    :close-on-press-escape="false"
    :wrapper-closable="false"
    :append-to-body="true"
    @close="visible=false"
    width="70%"
  >
    <div class="pdf-container">
      <iframe
        :src="`${path}/pdfjs/web/viewer.html?file=${form.url}`"
        frameborder="0"
        style="width: 100%; height: 100%;"
      ></iframe>
    </div>
  </el-dialog>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
export default {
  name: 'OperaCompanyUserWindow',
  extends: BaseOpera,
  components: { GlobalAlertWindow },
  data () {
    return {
      path: process.env.VUE_APP_CONTEXT_PATH == '/' ? '' : process.env.VUE_APP_CONTEXT_PATH,
      // è¡¨å•数据
      form: {
        url: ''
      }
    }
  },
  created () {
  }
}
</script>
<style lang="scss" scoped>
.address {
  ::v-deep .el-form-item {
    display: flex;
  }
  ::v-deep .el-form-item__content {
    flex: 1;
  }
  ::v-deep .el-select {
    width: 32%;
    .el-input__inner {
      width: 100%;
    }
  }
}
.pdf-container {
  width: 100%;
  height: calc(80vh - 100px);
  overflow-y: scroll;
}
::v-deep .el-dialog__header {
    padding: 0 !important;
    height: 40px;
    line-height: 40px;
    text-align: center;
    // background-color: rgba($color: #000000, $alpha: 0.3);
  }
::v-deep .window__footer {
  height: 1px;
}
// ::v-deep .el-dialog__body {
  // background-color: rgba($color: #000000, $alpha: 0.3);
// }
.ins-pdf-button-box {
  display: flex;
  padding: 20px;
  div {
    width: 80px;
    // background-color: #fff;
    background-color: #f5f5f5;
    margin-right: 10px;
    text-align: center;
    padding: 8px;
  }
  .last-style {
    border: 1px solid #666;
  }
}
</style>
admin/src/views/meeting/components/selectMember.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,267 @@
<template>
  <GlobalAlertWindow
    :title="title"
    :visible.sync="visible"
    :confirm-working="isWorking"
    @confirm="confirm"
  >
    <div class="select-container">
      <div class="tree">
        <div style="display: flex; margin-bottom: 5px;">
          <el-input
            placeholder="输入关键字进行过滤"
            v-model="filterText"
            clearable
            @input="inputAction"
            @keypress.enter.native="search"
          ></el-input>
          <el-button @click="search" style="margin-left: 5px;" type="primary">搜索</el-button>
        </div>
        <el-tree
          key="tree"
          v-if="!filterList.length"
          :data="data"
          :load="loadNode"
          lazy
        >
          <span class="custom-tree-node" slot-scope="{ node, data }">
            <span>{{ node.data.name }}</span>
            <el-checkbox @change="selectUser(node.data)" v-if="node.data.isUser" v-model="node.data.isSelect"></el-checkbox>
          </span>
        </el-tree>
        <div v-else>
          <div v-for="item in filterList" :key="item.id" class="custom-tree-node">
            <span>{{ item.realname }}</span>
            <el-checkbox @change="selectUser(item)" v-model="item.isSelect"></el-checkbox>
          </div>
        </div>
      </div>
      <div class="line"></div>
      <div class="selected">
        <div style="margin-bottom: 5px;">已选:{{ selectList.length }}</div>
        <div v-for="item in selectList" :key="item.id" class="custom-tree-node">
          <span>{{ item.name }}</span>
          <i class="el-icon-delete delete" @click="deleteAction(item)"></i>
        </div>
      </div>
    </div>
  </GlobalAlertWindow>
</template>
<script>
import BaseOpera from '@/components/base/BaseOpera'
import GlobalAlertWindow from '@/components/common/GlobalAlertWindow'
import { findTreeUser } from '@/api/system/department'
import { fetchList as userList } from '@/api/system/user'
export default {
  name: 'selectMember',
  extends: BaseOpera,
  components: { GlobalAlertWindow },
  data () {
    return {
      props: {
        label: 'name',
        children: 'zones',
        isLeaf: 'isUser'
      },
      data: [],
      filterText: '',
      filterList: [],
      selectList: [],
      // è¡¨å•数据
      form: {
        id: null,
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        name: '',
        roomId: '',
        startTime: '',
        endTime: '',
        content: ''
      },
      rootNode: {},
      // éªŒè¯è§„则
      rules: {
      }
    }
  },
  created () {
    this.config({
      api: '/meeting/bookings',
      'field.id': 'id'
    })
  },
  methods: {
    /**
     * æ‰“开窗口
     * @title çª—口标题
     * @target ç¼–辑的对象
     */
    open (title, target) {
      this.title = title
      this.visible = true
      this.filterList = []
      // æ–°å»º
      if (target == null) {
        this.$nextTick(() => {
          // this.$refs.form.resetFields()
          this.form[this.configData['field.id']] = null
        })
        return
      }
      // ç¼–辑
      this.$nextTick(() => {
        for (const key in this.form) {
          this.form[key] = target[key]
        }
      })
    },
    loadNode(node, resolve) {
      this.rootNode = node
      // console.log(node, resolve);
      if (node.data.isUser) {
        return resolve([])
      }
      let parentId = ''
      if (node.level === 0) {
        parentId = ''
      } else {
        parentId = node.data.id
      }
      findTreeUser({parentId})
        .then(res => {
          // this.data = [res]
          if (!parentId) {
            resolve([res])
          } else {
            let resolveList = []
            if (res.userList) {
              res.userList.forEach(item => {
                let index = this.selectList.findIndex(sel => sel.id == item.id)
                resolveList.push({
                  ...item,
                  name: item.realname,
                  isUser: true,
                  isSelect: index !== -1
                })
              });
            }
            if (res.children) {
              res.children.forEach(item => {
                resolveList.push(item)
              })
            }
            resolve(resolveList)
          }
        })
    },
    inputAction() {
      if (!this.filterText) {
        this.filterList = []
      }
    },
    search() {
      this.filterList = []
      if (this.filterText) {
        userList({
          page: 1,
          capacity: 9999,
          model: { realname: this.filterText },
        })
          .then(res => {
            // console.log(res);
            // this.filterList = res.records
            res.records.forEach(item => {
              let index = this.selectList.findIndex(sel => sel.id == item.id)
              this.filterList.push({
                  ...item,
                  isSelect: index !== -1
                })
            })
          })
      }
    },
    selectUser(item) {
      let index = this.selectList.findIndex(sel => sel.id == item.id)
      if (index !== -1) {
        this.selectList.splice(index, 1)
      } else {
        this.selectList.push({
          name: item.realname,
          id: item.id
        })
      }
    },
    deleteAction(item) {
      console.log(this.rootNode);
      this.selectList.splice(this.selectList.findIndex(sel => sel.id == item.id), 1)
      this.filterList.forEach(filter => {
        if (filter.id == item.id) {
          filter.isSelect = false
        }
      })
    }
  },
}
</script>
<style lang="scss" scoped>
.select-container {
  display: flex;
  height: 100%;
  .tree {
    padding: 0 10px 10px;
    box-sizing: border-box;
    width: calc(50% - 0.5px);
    min-height: 200px;
    // height: 100%;
  }
  .line {
    width: 1px;
    min-height: 200px;
    // height: 100%;
    background-color: #f7f7f7;
  }
  .selected {
    padding: 0 10px 10px;
    box-sizing: border-box;
    // background-color: red;
    // flex: 1;
    width: calc(50% - 0.5px);
    min-height: 200px;
    // height: 100%;
  }
}
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
}
.delete {
    box-sizing: border-box;
    line-height: 26px;
    margin-left: 10px;
    width: 16px;
    height: 16px;
    // background-color: #BFC3CB;
    color: #216EEE;
    border-radius: 50%;
    padding: 1.5px;
    cursor: pointer;
    &:hover {
      color: #ff0000;
    }
  }
</style>
admin/src/views/meeting/devices.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,156 @@
<template>
  <TableLayout :permissions="['business:devices:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="会议室" prop="roomId">
        <el-select
          v-model="searchForm.roomId"
          filterable
          clearable
          placeholder="请选择会议室"
        >
          <el-option v-for="item in room" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="状态" prop="status">
        <el-select
          v-model="searchForm.status"
          filterable
          clearable
          placeholder="请选择会议室"
        >
          <el-option :key="0" :value="0" label="启用" />
          <el-option :key="1" :value="1" label="禁用" />
        </el-select>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <!-- <el-button type="primary" :loading="isWorking.export" v-permissions="['business:devices:exportExcel']" @click="exportExcel">导出</el-button> -->
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:devices:create']">
        <li><el-button type="primary" @click="$refs.operaDevicesWindow.open('新建设备')" icon="el-icon-plus" v-permissions="['business:devices:create']">新建</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="index" prop="index" label="序号" align="center" min-width="50px"></el-table-column>
        <el-table-column prop="code" label="门禁ID" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="name" label="门禁名称" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="roomName" label="关联会议室" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="status" label="状态" align="center" min-width="100px">
          <template slot-scope="{row}">
            <el-switch
              v-model="row.status"
              active-color="#13ce66"
              inactive-color="#999"
              :active-value="0"
              :inactive-value="1"
              @change="changeStatus(row)"
            ></el-switch>
          </template>
        </el-table-column>
        <!-- <el-table-column prop="createDate" label="创建时间" min-width="100px"></el-table-column>
        <el-table-column prop="editor" label="更新人编码" min-width="100px"></el-table-column>
        <el-table-column prop="editDate" label="更新时间" min-width="100px"></el-table-column>
        <el-table-column prop="isdeleted" label="是否删除0否 1是" min-width="100px"></el-table-column>
        <el-table-column prop="remark" label="备注" min-width="100px"></el-table-column>
        <el-table-column prop="code" label="设备号(不可重复)" min-width="100px"></el-table-column> -->
        <el-table-column
          v-if="containPermissions(['business:devices:update', 'business:devices:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
          align="center"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaDevicesWindow.open('编辑设备', row)" icon="el-icon-edit" v-permissions="['business:devices:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:devices:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      ></pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaDevicesWindow ref="operaDevicesWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaDevicesWindow from '@/views/meeting/components/OperaDevicesWindow'
import { findList } from '@/api/meeting/rooms'
import { updateById } from '@/api/meeting/devices'
export default {
  name: 'Devices',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaDevicesWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: '',
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        name: '',
        code: '',
        roomId: '',
        status: ''
      },
      room: []
    }
  },
  provide() {
    return {
      room: () => this.room
    }
  },
  created () {
    this.config({
      module: '设备管理信息表',
      api: '/meeting/devices',
      'field.id': 'id',
      'field.main': 'id'
    })
    findList({status:0})
      .then(res => {
        this.room = res
      })
    this.search()
  },
  methods: {
    changeStatus(item) {
      updateById(item)
        .then(() => {
          this.$message.success('修改成功')
        })
        .catch(e => {
          this.$message.error(e)
        })
        .finally(() => {
          this.handlePageChange()
        })
    }
  },
}
</script>
admin/src/views/meeting/notice.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,110 @@
<template>
  <TableLayout :permissions="['business:notice:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="通知标题" prop="title">
        <el-input v-model="searchForm.title" placeholder="请输入通知标题" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="发布人" prop="creatorName">
        <el-input v-model="searchForm.creatorName" placeholder="请输入发布人" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <!-- <el-button type="primary" :loading="isWorking.export" v-permissions="['business:notice:exportExcel']" @click="exportExcel">导出</el-button> -->
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:notice:create', 'business:notice:delete']">
        <li><el-button type="primary" @click="$refs.operaNoticeWindow.open('新建消息通知')" icon="el-icon-plus" v-permissions="['business:notice:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:notice:delete']">删除</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column prop="title" label="标题" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="createDate" label="发布时间" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="creatorName" label="发布人" align="center" min-width="100px"></el-table-column>
        <!-- <el-table-column prop="editor" label="更新人编码" min-width="100px"></el-table-column>
        <el-table-column prop="editDate" label="更新时间" min-width="100px"></el-table-column>
        <el-table-column prop="isdeleted" label="是否删除0否 1是" min-width="100px"></el-table-column>
        <el-table-column prop="remark" label="备注" min-width="100px"></el-table-column>
        <el-table-column prop="memberId" label="用户编码(关联member表)" min-width="100px"></el-table-column>
        <el-table-column prop="content" label="内容" min-width="100px"></el-table-column>
        <el-table-column prop="objId" label="对象编码" min-width="100px"></el-table-column>
        <el-table-column prop="objType" label="对象类型 " min-width="100px"></el-table-column>
        <el-table-column prop="type" label="消息类型 0系统消息 1会议通知" min-width="100px"></el-table-column>
        <el-table-column prop="status" label="状态 0未读 1已读" min-width="100px"></el-table-column> -->
        <el-table-column
          v-if="containPermissions(['business:notice:update', 'business:notice:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
          align="center"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaNoticeWindow.open('编辑消息通知', row)" icon="el-icon-edit" v-permissions="['business:notice:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:notice:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaNoticeWindow ref="operaNoticeWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaNoticeWindow from '@/views/meeting/components/OperaNoticeWindow'
export default {
  name: 'Notice',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaNoticeWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: '',
        creatorName: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        remark: '',
        memberId: '',
        title: '',
        content: '',
        objId: '',
        objType: '',
        type: '',
        status: ''
      }
    }
  },
  created () {
    this.config({
      module: '消息通知信息表',
      api: '@/views/meeting/api/notice',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  }
}
</script>
admin/src/views/meeting/projects.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,133 @@
<template>
  <TableLayout :permissions="['business:projects:query']">
    <!-- æœç´¢è¡¨å• -->
    <!-- <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="主键" prop="id">
        <el-input v-model="searchForm.id" placeholder="请输入主键" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="创建人编码" prop="creator">
        <el-input v-model="searchForm.creator" placeholder="请输入创建人编码" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="创建时间" prop="createDate">
        <el-date-picker v-model="searchForm.createDate" value-format="yyyy-MM-dd" placeholder="请输入创建时间" @change="search"/>
      </el-form-item>
      <el-form-item label="更新人编码" prop="editor">
        <el-input v-model="searchForm.editor" placeholder="请输入更新人编码" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="更新时间" prop="editDate">
        <el-date-picker v-model="searchForm.editDate" value-format="yyyy-MM-dd" placeholder="请输入更新时间" @change="search"/>
      </el-form-item>
      <el-form-item label="是否删除0否 1是" prop="isdeleted">
        <el-input v-model="searchForm.isdeleted" placeholder="请输入是否删除0否 1是" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="名称(不可重复)" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称(不可重复)" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="备注" prop="remark">
        <el-input v-model="searchForm.remark" placeholder="请输入备注" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="图标" prop="imgurl">
        <el-input v-model="searchForm.imgurl" placeholder="请输入图标" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="状态 0启用 1禁用" prop="status">
        <el-input v-model="searchForm.status" placeholder="请输入状态 0启用 1禁用" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="排序码升序" prop="sortnum">
        <el-input v-model="searchForm.sortnum" placeholder="请输入排序码升序" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button type="primary" :loading="isWorking.export" v-permissions="['business:projects:exportExcel']" @click="exportExcel">导出</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form> -->
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:projects:create', 'business:projects:delete']">
        <li><el-button type="primary" @click="$refs.operaProjectsWindow.open('新建服务项目')" icon="el-icon-plus" v-permissions="['business:projects:create']">新建</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <el-table-column label="图标" align="center" min-width="100px">
          <template slot-scope="{row}">
            <!-- {{ row.imgurlfull }} -->
            <el-image
              v-if="!!row.imgurlfull"
              style="width: 80px; height: 40px;"
              :src="row.imgurlfull"
              :preview-src-list="[row.imgurlfull]"
            ></el-image>
          </template>
        </el-table-column>
        <el-table-column prop="name" label="名称" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="sortnum" label="排序码(升序)" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="createDate" label="创建时间" align="center" min-width="100px"></el-table-column>
        <el-table-column
          v-if="containPermissions(['business:projects:update', 'business:projects:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
          align="center"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaProjectsWindow.open('编辑服务项目', row)" icon="el-icon-edit" v-permissions="['business:projects:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:projects:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaProjectsWindow ref="operaProjectsWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaProjectsWindow from '@/views/meeting/components/OperaProjectsWindow'
export default {
  name: 'Projects',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaProjectsWindow },
  data () {
    return {
      // æœç´¢
      searchForm: {
        id: '',
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        name: '',
        remark: '',
        imgurl: '',
        status: '',
        sortnum: ''
      }
    }
  },
  created () {
    this.config({
      module: '服务项目信息表',
      api: '@/views/meeting/api/projects',
      'field.id': 'id',
      'field.main': 'id'
    })
    this.search()
  }
}
</script>
admin/src/views/meeting/roomRecord.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,154 @@
<template>
  <TableLayout :permissions="['business:roomrecord:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="会议室" prop="roomId">
        <el-select
            v-model="searchForm.roomId"
            filterable
            clearable
            placeholder="请选择会议室"
        >
          <el-option v-for="item in rooms" :key="item.id" :value="item.id" :label="item.name" />
        </el-select>
      </el-form-item>
      <el-form-item label="人员姓名" prop="name">
        <el-input v-model="searchForm.userName" placeholder="请输入人员姓名" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="会议主题" prop="name">
        <el-input v-model="searchForm.meeting" placeholder="请输入会议主题" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="类型" prop="status">
        <el-select v-model= "searchForm.objType" placeholder="请选择状态">
          <el-option  key="0"  value="0" label="管理员" />
          <el-option  key="1"  value="1" label="参会人员" />
          <el-option  key="2"  value="2" label="外部人员" />
        </el-select>
      </el-form-item>
      <el-form-item label="开门时间" prop="startTime">
        <el-date-picker
            v-model="date"
            type="datetimerange"
            range-separator="至"
            value-format="yyyy-MM-dd HH:mm:ss"
            start-placeholder="开始时间"
            end-placeholder="结束时间"
            @change="selectDate"
        ></el-date-picker>
        <!-- <el-date-picker v-model="searchForm.startTime" value-format="yyyy-MM-dd" placeholder="请输入开始时间" @change="search"/> -->
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button type="primary" :loading="isWorking.export" v-permissions="['business:roomrecord:exportExcel']" @click="exportExcel">导出</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
<!--      <ul class="toolbar" v-permissions="['business:roomrecord:create', 'business:roomrecord:delete']">
        <li><el-button type="primary" @click="$refs.operaRoomRecordWindow.open('新建会议室开门记录表')" icon="el-icon-plus" v-permissions="['business:roomrecord:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" icon="el-icon-delete" v-permissions="['business:roomrecord:delete']">删除</el-button></li>
      </ul>-->
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        @selection-change="handleSelectionChange"
      >
        <el-table-column label="人员姓名"  prop="userName" min-width="100px"></el-table-column>
        <el-table-column label="人员类型" prop="objType" min-width="100px">
            <template  slot-scope="{row}">
              <span v-if="row.objType==0" >管理员</span>
              <span v-else-if="row.objType==1">参会人员</span>
              <span v-else >外部人员</span>
            </template>
        </el-table-column>
        <el-table-column label="会议主题" prop="meeting" min-width="100px"></el-table-column>
        <el-table-column label="会议室" prop="roomName" min-width="100px"></el-table-column>
        <el-table-column prop="createDate" label="开门时间" min-width="100px"></el-table-column>
<!--        <el-table-column
          v-if="containPermissions(['business:roomrecord:update', 'business:roomrecord:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaRoomRecordWindow.open('编辑会议室开门记录表', row)" icon="el-icon-edit" v-permissions="['business:roomrecord:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" icon="el-icon-delete" v-permissions="['business:roomrecord:delete']">删除</el-button>
          </template>
        </el-table-column>-->
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      >
      </pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaRoomRecordWindow ref="operaRoomRecordWindow" @success="handlePageChange"/>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaRoomRecordWindow from '@/views/meeting/components/OperaRoomRecordWindow'
import { findList } from '@/api/meeting/rooms'
export default {
  name: 'RoomRecord',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaRoomRecordWindow },
  data () {
    return {
      date:[],
      // æœç´¢
      rooms: [
        { name: '201会议室', id: '0' }
      ],
      // æœç´¢
      searchForm: {
        userName: '',
        roomId: '',
        meeting: '',
        objType:null,
        startDate: null,
        endDate: null,
      }
    }
  },
  created () {
    this.config({
      module: '会议室开门记录表',
      api: '/meeting/roomRecord',
      'field.id': 'id',
      'field.main': 'id'
    })
    findList({})
        .then(res => {
          this.rooms = res
        })
    this.search()
  },
  methods: {
    selectDate(v) {
      this.searchForm.endDate = v[1]
      this.searchForm.startDate = v[0]
    },
    reset () {
      this.$refs.searchForm.resetFields()
      this.date = []
      this.searchForm =   {
        userName: '',
            roomId: '',
            meeting: '',
            objType:null,
            startDate: null,
            endDate: null,
      }
      this.search()
    }
  }
}
</script>
admin/src/views/meeting/roomStatistics.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,230 @@
<template>
  <TableLayout :permissions="['business:rooms:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="80px" inline>
      <!-- <el-form-item label="会议室名称" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
      </el-form-item> -->
      <!-- <el-form-item label="会议室" prop="roomId">
        <el-select
          v-model="searchForm.roomId"
          filterable
          clearable
          placeholder="请选择会议室"
        >
          <el-option
            v-for="item in rooms"
            :key="item.id"
            :value="item.id"
            :label="item.name"
          />
        </el-select>
      </el-form-item> -->
      <el-form-item label="年份" prop="yearNum">
        <!-- <div @click="selectMemberAction">
          <el-input v-model="searchForm.id" disabled placeholder="选择部门成员"></el-input>
        </div> -->
        <!-- {{ searchForm.sysList }} -->
        <el-select
          v-model="searchForm.yearNum"
          clearable
          placeholder="选择部门成员"
        >
          <el-option
            v-for="item in years"
            :key="item"
            :value="item"
            :label="`${item}å¹´`"
          ></el-option>
          <!-- <el-option :key="1" :value="1" label="禁用" /> -->
        </el-select>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:rooms:create', 'business:rooms:delete']">
        <li><el-button :loading="isWorking.export" v-permissions="['business:rooms:exportExcel']" @click="exportExcel">导出</el-button></li>
        <!-- <li><el-button type="primary" @click="$refs.operaRoomsWindow.open('新建会议室')" v-permissions="['business:rooms:create']">新建</el-button></li>
        <li><el-button @click="deleteByIdInBatch" v-permissions="['business:rooms:delete']">删除</el-button></li> -->
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <el-table-column prop="roomName" label="会议室" align="center" min-width="120px"></el-table-column>
        <el-table-column prop="januaryCount" label="一月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.januaryCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="二月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.februaryCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="三月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.marchCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="四月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.aprilCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="五月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.mayCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="六月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.juneCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="七月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.julyCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="八月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.augustCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="九月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.septemberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.octoberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十一月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.novemberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十二月" align="center" min-width="80px">
          <template slot-scope="{row}">
            {{ `${row.decemberCount}H` }}
          </template>
        </el-table-column>
      </el-table>
    </template>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import { getRoomStatistics, exportRoomStatistics } from '@/api/meeting/bookings'
// import { findList } from '@/api/meeting/rooms'
export default {
  name: 'Rooms',
  extends: BaseTable,
  components: { TableLayout,  },
  data () {
    return {
      years: [
        '2021', '2022', '2023'
      ],
      rooms: [],
      // æœç´¢
      searchForm: {
        yearNum: '',
        roomId: ''
      }
    }
  },
  created () {
    this.config({
      module: '会议室信息表',
      api: '/meeting/rooms',
      'field.id': 'id',
      'field.main': 'id'
    })
    // findList({})
    //   .then(res => {
    //     this.rooms = res
    //   })
    let tempYear = new Date().getFullYear()
    this.searchForm.yearNum = tempYear
    this.years = [tempYear-2, tempYear-1, tempYear]
    this.search()
  },
  methods: {
    // å¯¼å‡ºExcel
    exportExcel () {
      this.__checkApi()
      this.$dialog.exportConfirm('确认导出吗?')
        .then(() => {
          this.isWorking.export = true
          exportRoomStatistics({
            page: this.tableData.pagination.pageIndex,
            capacity: 1000000,
            model: this.searchForm,
            sorts: this.tableData.sorts
          })
            .then(response => {
              this.download(response)
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.isWorking.export = false
            })
        })
        .catch(() => {})
    },
    // é¡µç å˜æ›´å¤„理
    handlePageChange () {
      this.isWorking.search = true
      getRoomStatistics(this.searchForm.yearNum, this.searchForm.roomId)
        .then(data => {
          this.tableData.list = data
          // this.tableData.pagination.total = data.total
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking.search = false
        })
    },
    // selectMemberAction() {
    //   console.log('21212');
    //   this.$refs.selectMember.open('选择管理员')
    // },
    changeStatus(item) {
      updateById({
        id: item.id,
        status: item.status
      }).then(res => {
        this.search()
      })
    }
  },
}
</script>
<style scoped>
::v-deep .el-input.is-disabled .el-input__inner {
  background-color: #fff !important;
  cursor: pointer;
}
</style>
admin/src/views/meeting/rooms.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,236 @@
<template>
  <TableLayout :permissions="['business:rooms:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="会议室名称" prop="name">
        <el-input v-model="searchForm.name" placeholder="请输入名称" @keypress.enter.native="search"></el-input>
      </el-form-item>
      <el-form-item label="管理员" prop="sysList">
        <el-select
          v-model="searchForm.sysList"
          filterable
          clearable
          multiple
          placeholder="选择部门成员"
        >
          <el-option
            v-for="item in userList"
            :key="item.id"
            :value="item.id"
            :label="item.department?`${item.department.name}-${item.realname}`:item.realname"
            ></el-option>
            <!-- :label="`${item.department.name}-${item.realname}`" -->
          <!-- <el-option :key="1" :value="1" label="禁用" /> -->
        </el-select>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <!-- <el-button type="primary" :loading="isWorking.export" v-permissions="['business:rooms:exportExcel']" @click="exportExcel">导出</el-button> -->
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <ul class="toolbar" v-permissions="['business:rooms:create']">
        <li><el-button type="primary" @click="$refs.operaRoomsWindow.open('新建会议室')" v-permissions="['business:rooms:create']">新建</el-button></li>
        <!-- <li><el-button @click="deleteByIdInBatch" v-permissions="['business:rooms:delete']">删除</el-button></li> -->
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <!-- <el-table-column type="selection" width="55"></el-table-column> -->
        <el-table-column prop="name" label="会议室名称" align="center" min-width="120px" show-overflow-tooltip>
          <template slot-scope="{row}">
            <span class="long-title-style">{{ row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="startTime" label="开放时间" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.startTime}-${row.endTime}` }}
          </template>
        </el-table-column>
        <el-table-column prop="intervalTime" label="粒度(分钟)" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="limitNum" label="容纳人数" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="limitNum" label="管理员" min-width="140px" align="center" show-overflow-tooltip>
          <template slot-scope="{row}">
            <span class="long-title-style">{{ row.sysList.map(item => item.realName).join(',') }}</span>
            <!-- <ul>
              <li v-for="sys in row.sysList" :key="sys.id">{{sys.realName}}</li>
            </ul> -->
          </template>
        </el-table-column>
        <el-table-column prop="limitNum" label="可选服务项" align="center" min-width="140px" show-overflow-tooltip>
          <template slot-scope="{row}">
            <div class="long-title-style">{{ row.projectList.map(item => item.projectName).join('|') }}</div>
          </template>
        </el-table-column>
        <el-table-column prop="status" label="状态" align="center" min-width="100px">
          <template slot-scope="{row}">
            <el-switch
              v-model="row.status"
              active-color="#13ce66"
              inactive-color="#999"
              :active-value="0"
              :inactive-value="1"
              @change="changeStatus(row)"
            ></el-switch>
          </template>
        </el-table-column>
        <el-table-column prop="createDate" label="创建时间"  align="center" min-width="140px"></el-table-column>
        <!-- <el-table-column prop="editor" label="更新人编码" min-width="100px"></el-table-column>
        <el-table-column prop="editDate" label="更新时间" min-width="100px"></el-table-column>
        <el-table-column prop="isdeleted" label="是否删除0否 1是" min-width="100px"></el-table-column>
        <el-table-column prop="remark" label="备注" min-width="100px"></el-table-column>
        <el-table-column prop="imgurl" label="会议室图片" min-width="100px"></el-table-column>
        <el-table-column prop="tips" label="使用须知" min-width="100px"></el-table-column>
        <el-table-column prop="status" label="状态 0启用 1禁用" min-width="100px"></el-table-column> -->
        <el-table-column
          v-if="containPermissions(['business:rooms:update', 'business:rooms:delete'])"
          label="操作"
          min-width="120"
          fixed="right"
        >
          <template slot-scope="{row}">
            <el-button type="text" @click="$refs.operaRoomsWindow.open('编辑会议室', row)" v-permissions="['business:rooms:update']">编辑</el-button>
            <el-button type="text" @click="deleteById(row)" v-permissions="['business:rooms:delete']">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      ></pagination>
    </template>
    <!-- æ–°å»º/修改 -->
    <OperaRoomsWindow ref="operaRoomsWindow" @success="handlePageChange"/>
    <!-- <selectMember ref="selectMember" @done=""/> -->
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import OperaRoomsWindow from '@/views/meeting/components/OperaRoomsWindow'
import { fetchList as userList } from '@/api/system/user'
// import selectMember from '@/components/meeting/selectMember'
import { updateStatusById } from '@/api/meeting/rooms'
export default {
  name: 'Rooms',
  extends: BaseTable,
  components: { TableLayout, Pagination, OperaRoomsWindow },
  data () {
    return {
      userList: [],
      // æœç´¢
      searchForm: {
        id: '',
        creator: '',
        createDate: '',
        editor: '',
        editDate: '',
        isdeleted: '',
        name: '',
        remark: '',
        startTime: '',
        endTime: '',
        limitNum: '',
        imgurl: '',
        tips: '',
        status: '',
        intervalTime: '',
        sysList: []
      }
    }
  },
  provide() {
    return {
      userList: () => this.userList
    }
  },
  created () {
    this.config({
      module: '会议室信息表',
      api: '/meeting/rooms',
      'field.id': 'id',
      'field.main': 'id'
    })
    userList({
      page: 1,
      capacity: 9999,
      model: { realname: this.filterText },
    })
      .then(res => {
        this.userList = res.records
      })
    this.search()
  },
  methods: {
     // é¡µç å˜æ›´å¤„理
    handlePageChange (pageIndex) {
      this.__checkApi()
      this.tableData.pagination.pageIndex = pageIndex || this.tableData.pagination.pageIndex
      this.isWorking.search = true
      let sysList = [...this.searchForm.sysList]
      sysList = sysList.map(item => {
        return {userId: item}
      })
      console.log(sysList);
      this.api.fetchList({
        page: this.tableData.pagination.pageIndex,
        capacity: this.tableData.pagination.pageSize,
        model: {
          ...this.searchForm,
          sysList
        },
        sorts: this.tableData.sorts
      })
        .then(data => {
          this.tableData.list = data.records
          this.tableData.pagination.total = data.total
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking.search = false
        })
    },
    // selectMemberAction() {
    //   console.log('21212');
    //   this.$refs.selectMember.open('选择管理员')
    // },
    changeStatus(item) {
      updateStatusById({
        id: item.id,
        status: item.status
      })
        .then(() => {
          this.$message.success('修改成功')
        })
        .catch(e => {
          this.$message.error(e)
        })
        .finally(() => {
          this.handlePageChange()
        })
    }
  },
}
</script>
<style scoped>
::v-deep .el-input.is-disabled .el-input__inner {
  background-color: #fff !important;
  cursor: pointer;
}
</style>
admin/src/views/meeting/userStatistics.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,245 @@
<template>
  <TableLayout :permissions="['business:rooms:query']">
    <!-- æœç´¢è¡¨å• -->
    <el-form ref="searchForm" slot="search-form" :model="searchForm" label-width="100px" inline>
      <el-form-item label="人员" prop="userId">
        <el-select
          v-model="searchForm.userId"
          clearable
          filterable
          placeholder="选择人员"
        >
          <el-option
            v-for="item in sysList"
            :key="item.id"
            :value="item.id"
            :label="item.department?`${item.department.name}-${item.realname}`:item.realname"
            ></el-option>
            <!-- :label="item.name" -->
        </el-select>
      </el-form-item>
      <el-form-item label="年份" prop="yearNum">
        <el-select
          v-model="searchForm.yearNum"
          clearable
          placeholder="选择年份"
        >
          <el-option
            v-for="item in years"
            :key="item"
            :value="item"
            :label="`${item}å¹´`"
          ></el-option>
        </el-select>
      </el-form-item>
      <section>
        <el-button type="primary" @click="search">搜索</el-button>
        <el-button @click="reset">重置</el-button>
      </section>
    </el-form>
    <!-- è¡¨æ ¼å’Œåˆ†é¡µ -->
    <template v-slot:table-wrap>
      <!-- v-permissions="['business:rooms:create', 'business:rooms:delete']" -->
      <ul class="toolbar" >
        <!-- v-permissions="['business:rooms:exportExcel']" -->
        <li><el-button :loading="isWorking.export" @click="exportExcel">导出</el-button></li>
      </ul>
      <el-table
        v-loading="isWorking.search"
        :data="tableData.list"
        stripe
        border
        @selection-change="handleSelectionChange"
      >
        <!-- <el-table-column prop="roomName" label="会议室" align="center" min-width="100px"></el-table-column> -->
        <el-table-column prop="realname" label="姓名" align="center" min-width="100px"></el-table-column>
        <el-table-column prop="januaryCount" label="一月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.januaryCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="二月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.februaryCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="三月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.marchCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="四月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.aprilCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="五月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.mayCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="六月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.juneCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="七月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.julyCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="八月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.augustCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="九月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.septemberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.octoberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十一月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.novemberCount}H` }}
          </template>
        </el-table-column>
        <el-table-column prop="januaryCount" label="十二月" align="center" min-width="120px">
          <template slot-scope="{row}">
            {{ `${row.decemberCount}H` }}
          </template>
        </el-table-column>
      </el-table>
      <pagination
        @size-change="handleSizeChange"
        @current-change="handlePageChange"
        :pagination="tableData.pagination"
      ></pagination>
    </template>
  </TableLayout>
</template>
<script>
import BaseTable from '@/components/base/BaseTable'
import TableLayout from '@/layouts/TableLayout'
import Pagination from '@/components/common/Pagination'
import { getUserStatistics, exportUserStatistics } from '@/api/meeting/bookings'
import { fetchList as userList } from '@/api/system/user'
export default {
  name: 'Rooms',
  extends: BaseTable,
  components: { TableLayout, Pagination },
  data () {
    return {
      years: [
        '2021', '2022', '2023'
      ],
      sysList: [],
      // æœç´¢
      searchForm: {
        yearNum: '',
        userId: ''
      }
    }
  },
  created () {
    this.config({
      module: '会议室信息表',
      api: '/meeting/rooms',
      'field.id': 'id',
      'field.main': 'id'
    })
    let tempYear = new Date().getFullYear()
    this.searchForm.yearNum = tempYear
    this.years = [tempYear-2, tempYear-1, tempYear]
    // findList({})
    //   .then(res => {
    //     this.rooms = res
    //   })
    userList({
      page: 1,
      capacity: 9999,
      model: { realname: this.filterText },
    })
      .then(res => {
        console.log('userList', res);
        this.sysList = res.records
      })
    this.search()
  },
  methods: {
    // å¯¼å‡ºExcel
    exportExcel () {
      this.__checkApi()
      this.$dialog.exportConfirm('确认导出吗?')
        .then(() => {
          this.isWorking.export = true
          exportUserStatistics({
            page: this.tableData.pagination.pageIndex,
            capacity: 1000000,
            model: this.searchForm,
            sorts: this.tableData.sorts
          })
            .then(response => {
              this.download(response)
            })
            .catch(e => {
              this.$tip.apiFailed(e)
            })
            .finally(() => {
              this.isWorking.export = false
            })
        })
        .catch(() => {})
    },
    handlePageChange (pageIndex) {
      this.__checkApi()
      this.tableData.pagination.pageIndex = pageIndex || this.tableData.pagination.pageIndex
      this.isWorking.search = true
      getUserStatistics({
        page: this.tableData.pagination.pageIndex,
        capacity: this.tableData.pagination.pageSize,
        model: this.searchForm,
        sorts: this.tableData.sorts
      })
        .then(data => {
          this.tableData.list = data.records
          this.tableData.pagination.total = data.total
        })
        .catch(e => {
          this.$tip.apiFailed(e)
        })
        .finally(() => {
          this.isWorking.search = false
        })
    },
    // selectMemberAction() {
    //   console.log('21212');
    //   this.$refs.selectMember.open('选择管理员')
    // },
    changeStatus(item) {
      updateById({
        id: item.id,
        status: item.status
      }).then(res => {
        this.search()
      })
    }
  },
}
</script>
<style scoped>
::v-deep .el-input.is-disabled .el-input__inner {
  background-color: #fff !important;
  cursor: pointer;
}
</style>
replay_pid19008.log
ÎļþÒÑɾ³ý
replay_pid30652.log
ÎļþÒÑɾ³ý
server/meeting/meeting_admin/src/main/java/com/doumee/api/common/CaptchaController.java
@@ -1,5 +1,6 @@
package com.doumee.api.common;
import com.doumee.api.BaseController;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.model.ApiResponse;
import com.doumee.service.common.CaptchaService;
server/meeting/meeting_admin/src/main/java/com/doumee/api/common/PublicController.java
@@ -1,6 +1,7 @@
package com.doumee.api.common;
import com.alibaba.fastjson.JSONObject;
import com.doumee.api.BaseController;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.utils.Constants;
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/BookingTimeCloudController.java
@@ -36,6 +36,7 @@
    @PostMapping("/create")
    @CloudRequiredPermission("business:bookingtime:create")
    public ApiResponse create(@RequestBody BookingTime bookingTime,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        bookingTime.setLoginUserInfo(this.getLoginUser(token));
        return ApiResponse.success(bookingTimeService.create(bookingTime));
    }
@@ -50,7 +51,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:bookingtime:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -63,7 +64,8 @@
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:bookingtime:update")
    public ApiResponse updateById(@RequestBody BookingTime bookingTime) {
    public ApiResponse updateById(@RequestBody BookingTime bookingTime, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        bookingTime.setLoginUserInfo(this.getLoginUser(token));
        bookingTimeService.updateById(bookingTime);
        return ApiResponse.success(null);
    }
@@ -71,21 +73,21 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:bookingtime:query")
    public ApiResponse<PageData<BookingTime>> findPage (@RequestBody PageWrap<BookingTime> pageWrap) {
    public ApiResponse<PageData<BookingTime>> findPage (@RequestBody PageWrap<BookingTime> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(bookingTimeService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @CloudRequiredPermission("business:bookingtime:exportExcel")
    public void exportExcel (@RequestBody PageWrap<BookingTime> pageWrap, HttpServletResponse response) {
    public void exportExcel (@RequestBody PageWrap<BookingTime> pageWrap, HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        ExcelExporter.build(BookingTime.class).export(bookingTimeService.findPage(pageWrap).getRecords(), "会议室预约时间段关联表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @CloudRequiredPermission("business:bookingtime:query")
    public ApiResponse findById(@PathVariable Integer id) {
    public ApiResponse findById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(bookingTimeService.findById(id));
    }
@@ -94,7 +96,7 @@
    @ApiOperation("根据科室日期查询有效的时间段")
    @PostMapping("/findList")
    @CloudRequiredPermission("business:roomtime:query")
    public ApiResponse<List<BookingTime>> findPage (@RequestBody BookingTime pageWrap) {
    public ApiResponse<List<BookingTime>> findPage (@RequestBody BookingTime pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(bookingTimeService.findList(pageWrap));
    }
}
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/BookingsCloudController.java
ÎļþÃû´Ó server/meeting/meeting_admin/src/main/java/com/doumee/api/CloudBookingsController.java ÐÞ¸Ä
@@ -1,9 +1,9 @@
package com.doumee.api;
package com.doumee.cloud.admin;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.doumee.config.annotation.LoginNoRequired;
import com.doumee.api.BaseController;
import com.doumee.core.annotation.excel.ExcelExporter;
import com.doumee.core.annotation.pr.PreventRepeat;
import com.doumee.core.model.ApiResponse;
@@ -23,7 +23,6 @@
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
@@ -44,105 +43,106 @@
 * @author æ±Ÿè¹„蹄
 * @date 2023/05/04 18:18
 */
@Api(tags = "微服务-会议室相关接口")
@Api(tags = "会议室预定信息表")
@RestController
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/bookings")
public class CloudBookingsController extends BaseController {
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/business/bookings")
public class BookingsCloudController extends BaseController {
    @Autowired
    private BookingsService bookingsService;
    @ApiOperation("测试网管")
    @GetMapping("/test")
    public ApiResponse test() {
        return ApiResponse.success("会议室测试成功");
    }
    @LoginNoRequired
    @ApiOperation("测试无需登录成功")
    @GetMapping("/testNoLogin")
    public ApiResponse testNoLogin() {
        return ApiResponse.success("会议室管理测试无需登录成功");
    }
    @PreventRepeat
    @ApiOperation("新建")
    @PostMapping("/create")
    public ApiResponse create(@RequestBody Bookings bookings) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
    @RequiresPermissions("business:bookings:create")
    public ApiResponse create(@RequestBody Bookings bookings,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        LoginUserInfo user = getLoginUser(token);
        bookings.setLoginUserInfo(user);
        bookings.setCreator(user.getId());
        return ApiResponse.success(bookingsService.create(bookings));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    public ApiResponse deleteById(@PathVariable Integer id) {
        bookingsService.deleteById(id);
    @RequiresPermissions("business:bookings:delete")
    public ApiResponse deleteById(@PathVariable Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        bookingsService.deleteById(id,this.getLoginUser(token));
        return ApiResponse.success(null);
    }
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    @RequiresPermissions("business:bookings:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
        for (String id : idArray ){
            idList.add(Integer.valueOf(id));
        }
        bookingsService.deleteByIdInBatch(idList);
        bookingsService.deleteByIdInBatch(idList,this.getLoginUser(token));
        return ApiResponse.success(null);
    }
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    public ApiResponse updateById(@RequestBody Bookings bookings) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        bookings.setCreator(user.getId());
    @RequiresPermissions("business:bookings:update")
    public ApiResponse updateById(@RequestBody Bookings bookings,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        LoginUserInfo user = getLoginUser(token);
        bookings.setLoginUserInfo(user);
        bookings.setEditor(user.getId());
        bookingsService.updateById(bookings);
        return ApiResponse.success(null);
    }
    @ApiOperation("分页查询")
    @PostMapping("/page")
    public ApiResponse<PageData<Bookings>> findPage (@RequestBody PageWrap<Bookings> pageWrap) {
    @RequiresPermissions("business:bookings:query")
    public ApiResponse<PageData<Bookings>> findPage (@RequestBody PageWrap<Bookings> pageWrap,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        return ApiResponse.success(bookingsService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @RequiresPermissions("business:bookings:exportExcel")
    public void exportExcel (@RequestBody PageWrap<Bookings> pageWrap, HttpServletResponse response) {
    public void exportExcel (@RequestBody PageWrap<Bookings> pageWrap, HttpServletResponse response,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        ExcelExporter.build(Bookings.class).export(bookingsService.findPage(pageWrap).getRecords(), "会议室预定信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    public ApiResponse<MeetingDetailResponse> findById(@PathVariable Integer id) {
    @RequiresPermissions("business:bookings:query")
    public ApiResponse<MeetingDetailResponse> findById(@PathVariable Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        return ApiResponse.success(bookingsService.getMeetingDetail(id));
    }
    @ApiOperation("取消")
    @PostMapping("/cancelById")
    public ApiResponse cancelById(@RequestBody Bookings bookings) {
    @RequiresPermissions("business:bookings:update")
    public ApiResponse cancelById(@RequestBody Bookings bookings,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        bookings.setLoginUserInfo(this.getLoginUser(token));
        bookingsService.cancelById(bookings);
        return ApiResponse.success(null);
    }
    @ApiOperation("会议室使用时长统计")
    @GetMapping("/getRoomStatistics")
    @RequiresPermissions("business:bookings:update")
    public ApiResponse<List<RoomStatisticsVo>> getRoomStatistics(@RequestParam Integer yearNum, @RequestParam Integer roomId){
        return ApiResponse.success(bookingsService.getRoomStatistics(yearNum));
    }
    @ApiOperation("人员参加会议时常")
    @PostMapping("/getUserStatistics")
    @RequiresPermissions("business:bookings:update")
    public ApiResponse<PageData<UserStatisticsVo>> getUserStatistics(@RequestBody PageWrap<UserStatisticsDTO> pageWrap ){
        return ApiResponse.success(bookingsService.getUserStatistics(pageWrap));
    }
    @ApiOperation("人员参会时长统计导出Excel")
    @PostMapping("/exportUserStatistics")
    public void exportUserStatistics (@RequestBody PageWrap<UserStatisticsDTO> pageWrap,HttpServletResponse response) {
    @RequiresPermissions("business:bookings:exportExcel")
    public void exportUserStatistics (@RequestBody PageWrap<UserStatisticsDTO> pageWrap,HttpServletResponse response,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        List<UserStatisticsVo> records = bookingsService.getUserStatistics(pageWrap).getRecords();
        if (!CollectionUtils.isEmpty(records)){
@@ -165,7 +165,8 @@
    @ApiOperation("会议室使用时长统计导出Excel")
    @PostMapping("/exportRoomStatistics")
    public void exportRoomStatistics (@RequestBody PageWrap<UserStatisticsDTO> pageWrap,HttpServletResponse response) {
    @RequiresPermissions("business:bookings:exportExcel")
    public void exportRoomStatistics (@RequestBody PageWrap<UserStatisticsDTO> pageWrap,HttpServletResponse response,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        List<RoomStatisticsVo> roomStatistics = bookingsService.getRoomStatistics(pageWrap.getModel().getYearNum());
        if (!CollectionUtils.isEmpty(roomStatistics)){
            JSONArray o = (JSONArray) JSON.toJSON(roomStatistics);
@@ -198,7 +199,7 @@
            startTime =  DateUtil.getMonday();
            endTime = DateUtil.getSunday();
        }
        return ApiResponse.success(bookingsService.getMyJoinBookingMeet(getLoginUser().getId(), null,startTime,endTime));
        return ApiResponse.success(bookingsService.getMyJoinBookingMeet(getLoginUser(null).getId(), null,startTime,endTime));
    }
    /**
@@ -208,8 +209,6 @@
    @ApiOperation("获取用户当当月预约会议情况")
    @PostMapping("/findMothBookingMeet")
    public ApiResponse<List<DateTimeResourceDate>> findMothBookingMeet( @RequestParam(required = false) Integer roomId,String dateMonth){
        return ApiResponse.success(bookingsService.findMothBookingMeet(getLoginUser().getId(),roomId,dateMonth));
        return ApiResponse.success(bookingsService.findMothBookingMeet(getLoginUser(null).getId(),roomId,dateMonth));
    }
}
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/MeetingCloudController.java
@@ -49,7 +49,7 @@
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "yearMonth", value = "年月  yyyy-MM", required = true)
    })
    public ApiResponse<List<MonthDataResponse>> monthDay(@RequestParam String yearMonth) {
    public ApiResponse<List<MonthDataResponse>> monthDay(@RequestParam String yearMonth, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        List<String> dataList = DateUtil.getDayByMonth(yearMonth);
        List<MonthDataResponse> monthDataResponseList = new ArrayList<>();
@@ -86,7 +86,7 @@
//            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议主键", required = true),
    })
    public ApiResponse<MeetingDetailResponse> meetingDetail(@RequestParam Integer id) {
    public ApiResponse<MeetingDetailResponse> meetingDetail( @RequestHeader(Constants.HEADER_USER_TOKEN) String token,@RequestParam Integer id) {
        return ApiResponse.success("查询成功", bookingsService.getMeetingDetail(id));
    }
@@ -98,7 +98,6 @@
    })
    public ApiResponse<String> getQrCode(@RequestParam Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
//        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        return ApiResponse.success("查询成功", bookingsService.getQrCode(id,user.getId()));
    }
@@ -111,7 +110,6 @@
    })
    public void getQrCodeImg(@RequestParam Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token, HttpServletResponse response) throws  Exception {
        LoginUserInfo user = getLoginUser(token);
//        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        String content =bookingsService.getQrCode(id,user.getId());
@@ -126,9 +124,9 @@
    })
    public ApiResponse<Integer> reservationMeeting(@RequestBody BookingsRequest bookingsRequest,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
//        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        bookingsRequest.setCreator(user.getId());
        bookingsRequest.setEditor(user.getId());
        bookingsRequest.setLoginUserInfo(this.getLoginUser(token));
        return ApiResponse.success("操作成功",bookingsService.reservationMeeting(bookingsRequest));
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/MultifileCloudController.java
@@ -35,14 +35,14 @@
    @ApiOperation("新建")
    @PostMapping("/create")
    @CloudRequiredPermission("business:multifile:create")
    public ApiResponse create(@RequestBody Multifile multifile) {
    public ApiResponse create(@RequestBody Multifile multifile, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(multifileService.create(multifile));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:multifile:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
    public ApiResponse deleteById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        multifileService.deleteById(id);
        return ApiResponse.success(null);
    }
@@ -50,7 +50,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:multifile:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -63,7 +63,7 @@
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:multifile:update")
    public ApiResponse updateById(@RequestBody Multifile multifile) {
    public ApiResponse updateById(@RequestBody Multifile multifile, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        multifileService.updateById(multifile);
        return ApiResponse.success(null);
    }
@@ -71,21 +71,21 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:multifile:query")
    public ApiResponse<PageData<Multifile>> findPage (@RequestBody PageWrap<Multifile> pageWrap) {
    public ApiResponse<PageData<Multifile>> findPage (@RequestBody PageWrap<Multifile> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(multifileService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @CloudRequiredPermission("business:multifile:exportExcel")
    public void exportExcel (@RequestBody PageWrap<Multifile> pageWrap, HttpServletResponse response) {
    public void exportExcel (@RequestBody PageWrap<Multifile> pageWrap, HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        ExcelExporter.build(Multifile.class).export(multifileService.findPage(pageWrap).getRecords(), "附件上传信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @CloudRequiredPermission("business:multifile:query")
    public ApiResponse findById(@PathVariable Integer id) {
    public ApiResponse findById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(multifileService.findById(id));
    }
}
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/ProjectRelCloudController.java
@@ -35,14 +35,14 @@
    @ApiOperation("新建")
    @PostMapping("/create")
    @CloudRequiredPermission("business:projectrel:create")
    public ApiResponse create(@RequestBody ProjectRel projectRel) {
    public ApiResponse create(@RequestBody ProjectRel projectRel, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectRelService.create(projectRel));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:projectrel:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
    public ApiResponse deleteById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        projectRelService.deleteById(id);
        return ApiResponse.success(null);
    }
@@ -50,7 +50,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:projectrel:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -63,7 +63,7 @@
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:projectrel:update")
    public ApiResponse updateById(@RequestBody ProjectRel projectRel) {
    public ApiResponse updateById(@RequestBody ProjectRel projectRel, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        projectRelService.updateById(projectRel);
        return ApiResponse.success(null);
    }
@@ -71,21 +71,21 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:projectrel:query")
    public ApiResponse<PageData<ProjectRel>> findPage (@RequestBody PageWrap<ProjectRel> pageWrap) {
    public ApiResponse<PageData<ProjectRel>> findPage (@RequestBody PageWrap<ProjectRel> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectRelService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @CloudRequiredPermission("business:projectrel:exportExcel")
    public void exportExcel (@RequestBody PageWrap<ProjectRel> pageWrap, HttpServletResponse response) {
    public void exportExcel (@RequestBody PageWrap<ProjectRel> pageWrap, HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        ExcelExporter.build(ProjectRel.class).export(projectRelService.findPage(pageWrap).getRecords(), "服务项目关联表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @CloudRequiredPermission("business:projectrel:query")
    public ApiResponse findById(@PathVariable Integer id) {
    public ApiResponse findById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectRelService.findById(id));
    }
}
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/ProjectsCloudController.java
@@ -45,7 +45,7 @@
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:projects:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
    public ApiResponse deleteById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        projectsService.deleteById(id);
        return ApiResponse.success(null);
    }
@@ -53,7 +53,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:projects:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -75,21 +75,21 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:projects:query")
    public ApiResponse<PageData<Projects>> findPage (@RequestBody PageWrap<Projects> pageWrap) {
    public ApiResponse<PageData<Projects>> findPage (@RequestBody PageWrap<Projects> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectsService.findPage(pageWrap));
    }
    @ApiOperation("导出Excel")
    @PostMapping("/exportExcel")
    @CloudRequiredPermission("business:projects:exportExcel")
    public void exportExcel (@RequestBody PageWrap<Projects> pageWrap, HttpServletResponse response) {
    public void exportExcel (@RequestBody PageWrap<Projects> pageWrap, HttpServletResponse response, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        ExcelExporter.build(Projects.class).export(projectsService.findPage(pageWrap).getRecords(), "服务项目信息表", response);
    }
    @ApiOperation("根据ID查询")
    @GetMapping("/{id}")
    @CloudRequiredPermission("business:projects:query")
    public ApiResponse findById(@PathVariable Integer id) {
    public ApiResponse findById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectsService.findById(id));
    }
@@ -98,7 +98,7 @@
    @ApiOperation("会议关联的项目")
    @PostMapping("/findListByObjId")
    @CloudRequiredPermission("business:projects:query")
    public ApiResponse<List<ProjectsResponse>> findListByObjId (@RequestParam Integer objId, @RequestParam Integer objType) {
    public ApiResponse<List<ProjectsResponse>> findListByObjId (@RequestParam Integer objId, @RequestParam Integer objType, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(projectsService.getProjectsList(objId,objType));
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/RoomsCloudController.java
@@ -48,14 +48,15 @@
    @ApiOperation("新建")
    @PostMapping("/create")
    @CloudRequiredPermission("business:rooms:create")
    public ApiResponse create(@RequestBody Rooms rooms) {
    public ApiResponse create(@RequestBody Rooms rooms,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        rooms.setLoginUserInfo(this.getLoginUser(token));
        return ApiResponse.success(roomsService.create(rooms));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:rooms:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
    public ApiResponse deleteById(@PathVariable Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        roomsService.deleteById(id);
        return ApiResponse.success(null);
    }
@@ -63,7 +64,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:rooms:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -76,7 +77,8 @@
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:rooms:update")
    public ApiResponse updateById(@RequestBody Rooms rooms) {
    public ApiResponse updateById(@RequestBody Rooms rooms,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        rooms.setLoginUserInfo(this.getLoginUser(token));
        roomsService.updateById(rooms);
        return ApiResponse.success(null);
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/admin/UserRelCloudController.java
@@ -35,14 +35,14 @@
    @ApiOperation("新建")
    @PostMapping("/create")
    @CloudRequiredPermission("business:userrel:create")
    public ApiResponse create(@RequestBody UserRel userRel) {
    public ApiResponse create(@RequestBody UserRel userRel, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(userRelService.create(userRel));
    }
    @ApiOperation("根据ID删除")
    @GetMapping("/delete/{id}")
    @CloudRequiredPermission("business:userrel:delete")
    public ApiResponse deleteById(@PathVariable Integer id) {
    public ApiResponse deleteById(@PathVariable Integer id, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        userRelService.deleteById(id);
        return ApiResponse.success(null);
    }
@@ -50,7 +50,7 @@
    @ApiOperation("批量删除")
    @GetMapping("/delete/batch")
    @CloudRequiredPermission("business:userrel:delete")
    public ApiResponse deleteByIdInBatch(@RequestParam String ids) {
    public ApiResponse deleteByIdInBatch(@RequestParam String ids, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        String [] idArray = ids.split(",");
        List<Integer> idList = new ArrayList<>();
        for (String id : idArray) {
@@ -63,7 +63,7 @@
    @ApiOperation("根据ID修改")
    @PostMapping("/updateById")
    @CloudRequiredPermission("business:userrel:update")
    public ApiResponse updateById(@RequestBody UserRel userRel) {
    public ApiResponse updateById(@RequestBody UserRel userRel, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        userRelService.updateById(userRel);
        return ApiResponse.success(null);
    }
@@ -71,7 +71,7 @@
    @ApiOperation("分页查询")
    @PostMapping("/page")
    @CloudRequiredPermission("business:userrel:query")
    public ApiResponse<PageData<UserRel>> findPage (@RequestBody PageWrap<UserRel> pageWrap) {
    public ApiResponse<PageData<UserRel>> findPage (@RequestBody PageWrap<UserRel> pageWrap, @RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success(userRelService.findPage(pageWrap));
    }
server/meeting/meeting_admin/src/main/resources/bootstrap.yml
@@ -17,7 +17,7 @@
      password: nacos
      config:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: dev_renkang
        namespace: dmvisit
        username: nacos
        password: nacos
#        file-extension: yaml
@@ -25,7 +25,7 @@
#        data-id: com.doumee.meeting.admin
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: dev_renkang
        namespace: dmvisit
        username: nacos
        password: nacos
      # å®‰å…¨é…ç½®
server/meeting/meeting_admin/src/main/resources/logback-spring.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%highlight(%date{yyyy-MM-dd HH:mm:ss}) | %highlight(%-5level) | %highlight(%thread) | %highlight(%logger) | %msg%n</pattern>
        </layout>
    </appender>
    <property name="log.path" value="logs/meetingAdmin"></property>
    <property name="log.fileSize" value="100MB"></property>
    <property name="log.historyDays" value="7"></property>
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <!--匹配就舍去-->
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>${log.path}/info.%d.%i.log</fileNamePattern>
            <maxFileSize>${log.fileSize}</maxFileSize>
            <maxHistory>${log.historyDays}</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
        </encoder>
        <!--滚动策略-->
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--路径-->
            <fileNamePattern>${log.path}/error.%d.%i.log</fileNamePattern>
            <maxFileSize>${log.fileSize}</maxFileSize>
            <maxHistory>${log.historyDays}</maxHistory>
            <totalSizeCap>1GB</totalSizeCap>
        </rollingPolicy>
    </appender>
    <!-- å¼‚步写入日志 -->
    <appender name ="ASYNC" class= "ch.qos.logback.classic.AsyncAppender">
        <!-- ä¸ä¸¢å¤±æ—¥å¿—.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
        <discardingThreshold >0</discardingThreshold>
        <!-- æ›´æ”¹é»˜è®¤çš„队列的深度,该值会影响性能.默认值为256 -->
        <queueSize>512</queueSize>
        <!-- æ·»åŠ é™„åŠ çš„appender,最多只能添加一个 -->
        <appender-ref ref ="fileInfoLog"/>
    </appender>
    <root level="info">
        <appender-ref ref="consoleLog"/>
        <appender-ref ref="fileInfoLog"/>
        <appender-ref ref="fileErrorLog"/>
    </root>
</configuration>
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/BookingTime.java
@@ -1,6 +1,7 @@
package com.doumee.dao.business.model;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -18,7 +19,7 @@
@Data
@ApiModel("会议室预约时间段关联表")
@TableName("`meeting_book_time`")
public class BookingTime {
public class BookingTime extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -31,7 +32,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -40,8 +40,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Bookings.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import com.doumee.dao.system.model.Multifile;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -22,7 +23,7 @@
@Data
@ApiModel("会议室预定信息表")
@TableName("`meeting_book`")
public class Bookings {
public class Bookings extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Devices.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -22,7 +23,7 @@
@Data
@ApiModel("设备管理信息表")
@TableName("`devices`")
public class Devices {
public class Devices extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -35,7 +36,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -44,8 +44,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/ProjectRel.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
@Data
@ApiModel("服务项目关联表")
@TableName("`meeting_project_rel`")
public class ProjectRel {
public class ProjectRel extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -32,7 +33,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -41,8 +41,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Projects.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
@Data
@ApiModel("服务项目信息表")
@TableName("`meeting_projects`")
public class Projects {
public class Projects extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -32,7 +33,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -41,8 +41,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/RoomRecord.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -20,7 +21,7 @@
@Data
@ApiModel("会议室开门记录表")
@TableName("`meeting_room_record`")
public class RoomRecord {
public class RoomRecord extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/RoomTime.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
@Data
@ApiModel("会议室预约时间段信息表")
@TableName("`meeting_room_time`")
public class RoomTime {
public class RoomTime extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -32,7 +33,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -41,8 +41,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/Rooms.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import com.doumee.dao.system.model.SystemUser;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -23,7 +24,7 @@
@Data
@ApiModel("会议室信息表")
@TableName("`meeting_rooms`")
public class Rooms {
public class Rooms extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/model/UserRel.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -20,7 +21,7 @@
@Data
@ApiModel("会议室管理员和参会人员关联表")
@TableName("`meeting_user_rel`")
public class UserRel {
public class UserRel extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
@@ -33,7 +34,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -42,8 +42,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/meeting/meeting_service/src/main/java/com/doumee/dao/web/request/BookingsRequest.java
@@ -1,5 +1,6 @@
package com.doumee.dao.web.request;
import com.doumee.core.model.LoginUserModel;
import com.doumee.dao.business.model.BookingTime;
import com.doumee.dao.system.model.Multifile;
import com.doumee.dao.business.model.ProjectRel;
@@ -19,7 +20,7 @@
 */
@Data
@ApiModel("会议室预定请求类")
public class BookingsRequest {
public class BookingsRequest extends LoginUserModel {
    @ApiModelProperty(value = "主键", example = "1")
    private Integer id;
server/meeting/meeting_service/src/main/java/com/doumee/service/business/BookingsService.java
@@ -1,6 +1,7 @@
package com.doumee.service.business;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.dao.admin.response.DevWgResponseParam;
@@ -39,21 +40,21 @@
     *
     * @param id ä¸»é”®
     */
    void deleteById(Integer id);
    void deleteById(Integer id,LoginUserInfo user);
    /**
     * åˆ é™¤
     *
     * @param bookings å®žä½“对象
     */
    void delete(Bookings bookings);
    void delete(Bookings bookings,LoginUserInfo user);
    /**
     * æ‰¹é‡ä¸»é”®åˆ é™¤
     *
     * @param ids ä¸»é”®é›†
     */
    void deleteByIdInBatch(List<Integer> ids);
    void deleteByIdInBatch(List<Integer> ids, LoginUserInfo user);
    /**
     * ä¸»é”®æ›´æ–°
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/BookingsServiceImpl.java
@@ -299,8 +299,7 @@
    }
    @Override
    public void deleteById(Integer id) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
    public void deleteById(Integer id,LoginUserInfo user) {
        Bookings bookings = new Bookings();
        bookings.setId(id);
        bookings.setIsdeleted(MeetConstants.ONE);
@@ -310,14 +309,13 @@
    }
    @Override
    public void delete(Bookings bookings) {
    public void delete(Bookings bookings,LoginUserInfo user) {
        UpdateWrapper<Bookings> deleteWrapper = new UpdateWrapper<>(bookings);
        bookingsMapper.delete(deleteWrapper);
    }
    @Override
    public void deleteByIdInBatch(List<Integer> ids) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
    public void deleteByIdInBatch(List<Integer> ids,LoginUserInfo user) {
        if (CollectionUtils.isEmpty(ids)) {
            return;
        }
@@ -349,8 +347,7 @@
        if(dbBookings.getStatus().equals(MeetConstants.ONE)){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(), "本次操作失败,预约状态已流转");
        }
        LoginUserInfo user = new LoginUserInfo();
        user.setId(bookings.getCreator());
        LoginUserInfo user = bookings.getLoginUserInfo();
        isCreateParamValid(bookings, user);
        bookings.setEditDate(new Date());
        bookings.setEditor(user.getId());
@@ -385,6 +382,9 @@
    @Override
    public void cancelById(Bookings bs) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        if(user == null){
            user = bs.getLoginUserInfo();
        }
/*
        if(Objects.isNull(bookings)||bookings.getId()==null){
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(), ResponseStatus.BAD_REQUEST.getMessage());
@@ -478,7 +478,7 @@
        }
        queryWrapper.orderByDesc(Bookings::getCreateDate);
        String path = systemDictDataBiz.queryByCode(MeetConstants.SYSTEM, MeetConstants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String path = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        SimpleDateFormat format = new SimpleDateFormat("MM-dd HH:mm");
        SimpleDateFormat format1 = new SimpleDateFormat("HH:mm");
@@ -551,7 +551,7 @@
        queryWrapper.orderByDesc(Bookings::getCreateDate);
//        String path = systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String path = systemDictDataBiz.queryByCode(MeetConstants.SYSTEM, MeetConstants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String path = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        Bookings result = bookingsJoinMapper.selectOne(queryWrapper.last("limit 1"));
        if (result != null) {
@@ -779,10 +779,9 @@
                        .orderByDesc(!Objects.isNull(pageWrap.getModel().getStatus())&&pageWrap.getModel().getStatus().equals(MeetConstants.TWO),"a.START_TIME")
                        .orderByAsc(Objects.isNull(pageWrap.getModel().getStatus())||pageWrap.getModel().getStatus().equals(MeetConstants.ONE),"a.START_TIME")
        );
        String prefixUrl = systemDictDataBiz.queryByCode(MeetConstants.SYSTEM, MeetConstants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        ;
        String path = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        page.getRecords().forEach(i -> {
            i.setPrefixUrl(prefixUrl);
            i.setPrefixUrl(path);
        });
        return page;
    }
@@ -810,7 +809,7 @@
        //参会人员列表
        SystemUser param = new SystemUser();
        List<SystemUser> userResponseList = systemUserService.findList(param);
        String avatarPath = systemDictDataBiz.queryByCode(MeetConstants.SYSTEM, MeetConstants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String avatarPath = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.MEMBER_IMG).getCode();
        userResponseList.forEach(i -> {
            if(StringUtils.isNotBlank(i.getAvatar())){
                i.setAvatar(avatarPath+i.getAvatar());
@@ -818,7 +817,7 @@
        });
        meetingDetailResponse.setUserResponseList(userResponseList);
        //服务项
        String projectsPath = systemDictDataBiz.queryByCode(MeetConstants.SYSTEM, MeetConstants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String projectsPath = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        List<ProjectsResponse> projectsResponseList = projectsService.getProjectsList(id, MeetConstants.ONE);
        projectsResponseList.forEach(i -> {
            i.setPrefixUrl(projectsPath);
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/ProjectsServiceImpl.java
@@ -47,6 +47,7 @@
        insert.setImgurl(projects.getImgurl());
        insert.setStatus(MeetConstants.ZERO);
        insert.setSortnum(projects.getSortnum());
        insert.setCreateDate(new Date());
        projectsMapper.insert(insert);
        return projects.getId();
    }
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/RoomsServiceImpl.java
@@ -73,7 +73,9 @@
    @Transactional(rollbackFor = {BusinessException.class, Exception.class})
    public Integer create(Rooms rooms) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        if(user ==null){
            user = rooms.getLoginUserInfo();
        }
        isCreateParamValid(rooms, user);
        Calendar starttime = Calendar.getInstance();
@@ -102,12 +104,11 @@
        rooms.setStartTime(DateUtil.formatDate(starttime.getTime(), "yyyy-MM-dd HH:mm:ss"));
        rooms.setEndTime(DateUtil.formatDate(endtime.getTime(), "yyyy-MM-dd HH:mm:ss"));
        //TODO æ›´æ–°ä¼šè®®å®¤æ—¶é—´æ®µ
        //  æ›´æ–°ä¼šè®®å®¤æ—¶é—´æ®µ
        updateRoomTimes(rooms, user);
        //TODO æ·»åŠ ç®¡ç†äººå‘˜
        //  æ·»åŠ ç®¡ç†äººå‘˜
        updateManager(rooms, user);
        //TODO æ·»åŠ ç®¡æœåŠ¡é¡¹ç›®
        //  æ·»åŠ ç®¡æœåŠ¡é¡¹ç›®
        updateProjectRel(rooms, user);
        return rooms.getId();
    }
@@ -324,7 +325,9 @@
    public void updateById(Rooms rooms) {
        LoginUserInfo user = (LoginUserInfo) SecurityUtils.getSubject().getPrincipal();
        if(user ==null){
            user = rooms.getLoginUserInfo();
        }
        isCreateParamValid(rooms, user);
        Calendar starttime = Calendar.getInstance();
@@ -450,7 +453,7 @@
            queryWrapper.exists("select u.id from user_rel u where u.ISDELETED=0 and u.OBJ_ID =t.id and  u.USER_ID in (" +     StringUtils.strip(collect.toString(),"[]")+" )");
        }
        String path = systemDictDataBiz.queryByCode(Constants.SYSTEM, Constants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String path = systemDictDataBiz.queryByCode(Constants.FTP, Constants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        IPage<Rooms> result = roomsJoinMapper.selectJoinPage(page, Rooms.class, queryWrapper);
        result.getRecords().stream().forEach(s ->{
@@ -536,8 +539,8 @@
                .exists(" select 1 from user_rel u where u.USER_ID = "+pageWrap.getModel().getUserId()+" and u.ISDELETED = 0 and u.OBJ_ID = rooms.id and u.OBJ_TYPE = 0  ")
                .orderByDesc("CREATE_DATE")
        );
        String prefixUrl = systemDictDataBiz.queryByCode(Constants.SYSTEM, Constants.FILE_DIR).getCode()
                + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String prefixUrl = systemDictDataBiz.queryByCode(Constants.FTP, Constants.FTP_RESOURCE_PATH).getCode()
                + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        page.getRecords().forEach(s->{
            s.setPrefixUrl(prefixUrl);
@@ -573,7 +576,7 @@
            throw new BusinessException(ResponseStatus.DATA_EMPTY.getCode(),"未查询到会议室信息");
        }
        String prefixUrl = systemDictDataBiz.queryByCode(Constants.SYSTEM, Constants.FILE_DIR).getCode() + systemDictDataBiz.queryByCode(MeetConstants.OSS, MeetConstants.PROJECTS).getCode();
        String prefixUrl = systemDictDataBiz.queryByCode(Constants.FTP, Constants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        roomsResponse.setPrefixUrl(prefixUrl);
server/meeting/pom.xml
@@ -20,12 +20,21 @@
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
       <dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.3.12.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--   <dependency>
               <groupId>org.springframework.cloud</groupId>
               <artifactId>spring-cloud-starter-bootstrap</artifactId>
           </dependency>-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <!-- <version>2.2.7.RELEASE</version>-->
        </dependency>
        <!--<dependency>
            <groupId>org.springframework.cloud</groupId>
@@ -33,20 +42,10 @@
        </dependency>-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<!--            <version>2.2.7.RELEASE</version>-->
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
<!--            <version>2.2.7.RELEASE</version>-->
            <!-- <version>2.2.7.RELEASE</version>-->
        </dependency>
        <!-- Swagger å¢žå¼ºknife4j å¾®æœåŠ¡starter -->
        <dependency>
            <groupId>com.github.xiaoymin</groupId>
            <artifactId>knife4j-micro-spring-boot-starter</artifactId>
            <version>3.0.3</version>
            <scope>compile</scope>
        </dependency>
        <!-- æŽ¥å£æ–‡æ¡£ -->
    </dependencies>
</project>
server/system_gateway/src/main/resources/bootstrap.yml
@@ -14,7 +14,7 @@
      password: nacos
      discovery:
        server-addr: http://175.27.187.84:8848 #配置Nacos地址
        namespace: dev_renkang
        namespace: dmvisit
        username: nacos
        password: nacos
    gateway:
server/system_service/src/main/java/com/doumee/config/cloudfilter/LoginHandlerInterceptor.java
@@ -14,8 +14,11 @@
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Enumeration;
public class LoginHandlerInterceptor implements HandlerInterceptor {
@@ -33,9 +36,17 @@
        Class<?> beanType = handlerMethod.getBeanType();
        if (!beanType.isAnnotationPresent(LoginNoRequired.class) && !handlerMethod.hasMethodAnnotation(LoginNoRequired.class)) {
            //获取token
            Cookie[]  cookies =   request.getCookies();
            String token = request.getHeader(Constants.HEADER_USER_TOKEN);  // ä»Ž http è¯·æ±‚头中取出 token
            if(StringUtils.isBlank(token)){
                for(Cookie c :cookies){
                    if(StringUtils.equals(c.getName(),Constants.HEADER_USER_TOKEN)){
                        token = c.getValue();
                    }
                }
            }
            if (StringUtils.isNotBlank(token)) {
              LoginUserInfo user =   checkLogin(request,response);
              LoginUserInfo user =   checkLogin(token);
                if (handlerMethod.hasMethodAnnotation(CloudRequiredPermission.class)) {
                    CloudRequiredPermission p = handlerMethod.getMethodAnnotation(CloudRequiredPermission.class);
                    if(p.value()!=null && p.value().length>0){
@@ -64,8 +75,7 @@
        return true;
    }
    private LoginUserInfo checkLogin(HttpServletRequest request, HttpServletResponse response) {
        String token = request.getHeader(Constants.HEADER_USER_TOKEN);
    private LoginUserInfo checkLogin(String token) {
        if (token == null || token.isEmpty()) {
            throw new BusinessException(ResponseStatus.NO_LOGIN.getCode(),"未登录");
        }
server/system_service/src/main/java/com/doumee/core/utils/Constants.java
@@ -253,7 +253,7 @@
    public static final String ACCESS_KEY = "ACCESS_KEY";
    public static final String ENDPOINT = "ENDPOINT";
    public static final String RESOURCE_PATH = "RESOURCE_PATH";
    public static final String RESOURCE_PATH = "FTP_RESOURCE_PATH";
    //发送会议开始  å®šæ—¶æå‰å¤šå°‘分钟发送
    public static final String SYSTEM ="SYSTEM";
server/system_service/src/main/java/com/doumee/dao/system/model/Multifile.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
@Data
@ApiModel("附件上传信息表")
@TableName("`multifile`")
public class Multifile {
public class Multifile extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/Notices.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.LoginUserModel;
import com.doumee.core.utils.Constants;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@@ -21,7 +22,7 @@
@Data
@ApiModel("系统消息信息表")
@TableName("`notices`")
public class Notices {
public class Notices  extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDataPermission.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -22,7 +23,7 @@
@Data
@ApiModel("数据权限配置")
@TableName("SYSTEM_DATA_PERMISSION")
public class SystemDataPermission implements Serializable {
public class SystemDataPermission extends LoginUserModel implements Serializable  {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDepartment.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -21,7 +22,7 @@
 */
@Data
@ApiModel("部门")
public class SystemDepartment implements Serializable {
public class SystemDepartment extends LoginUserModel implements Serializable  {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDepartmentUser.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -16,7 +17,7 @@
 */
@Data
@ApiModel("部门用户")
public class SystemDepartmentUser implements Serializable {
public class SystemDepartmentUser extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDict.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
 */
@Data
@ApiModel("字典")
public class SystemDict implements Serializable {
public class SystemDict extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemDictData.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
 */
@Data
@ApiModel("字典数据")
public class SystemDictData implements Serializable {
public class SystemDictData extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemLoginLog.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -18,7 +19,7 @@
 */
@Data
@ApiModel("登录日志")
public class SystemLoginLog {
public class SystemLoginLog extends LoginUserModel {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemMenu.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -21,7 +22,7 @@
 */
@Data
@ApiModel("系统菜单")
public class SystemMenu implements Serializable {
public class SystemMenu extends LoginUserModel implements Serializable  {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPermission.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
 */
@Data
@ApiModel("系统权限")
public class SystemPermission implements Serializable  {
public class SystemPermission extends LoginUserModel implements Serializable  {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPosition.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -21,7 +22,7 @@
 */
@Data
@ApiModel("岗位")
public class SystemPosition implements Serializable {
public class SystemPosition extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemPositionUser.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -16,7 +17,7 @@
 */
@Data
@ApiModel("岗位用户")
public class SystemPositionUser implements Serializable {
public class SystemPositionUser extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRole.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -19,7 +20,7 @@
 */
@Data
@ApiModel("系统角色")
public class SystemRole implements Serializable {
public class SystemRole extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRoleMenu.java
@@ -1,5 +1,6 @@
package com.doumee.dao.system.model;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -16,7 +17,7 @@
 */
@Data
@ApiModel("角色菜单关联")
public class SystemRoleMenu implements Serializable {
public class SystemRoleMenu  extends LoginUserModel implements Serializable {
    @ApiModelProperty(value = "主键", example = "1")
    @TableId(type = IdType.AUTO)
server/system_service/src/main/java/com/doumee/dao/system/model/SystemRolePermission.java
@@ -1,5 +1,6 @@
package com.doumee.dao.system.model;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -16,7 +17,7 @@
 */
@Data
@ApiModel("角色权限关联")
public class SystemRolePermission implements Serializable {
public class SystemRolePermission extends LoginUserModel implements Serializable {
    @ApiModelProperty(value = "主键", example = "1")
    @TableId(type = IdType.AUTO)
server/system_service/src/main/java/com/doumee/dao/system/model/SystemTraceLog.java
@@ -1,6 +1,7 @@
package com.doumee.dao.system.model;
import com.doumee.core.annotation.excel.ExcelColumn;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -17,7 +18,7 @@
 */
@Data
@ApiModel("跟踪日志")
public class SystemTraceLog implements Serializable {
public class SystemTraceLog extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemUser.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.doumee.core.constants.OperaType;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -25,7 +26,7 @@
@Data
@ApiModel("系统用户")
@TableName("`SYSTEM_USER`")
public class SystemUser implements Serializable {
public class SystemUser extends LoginUserModel implements Serializable {
    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "主键", example = "1")
server/system_service/src/main/java/com/doumee/dao/system/model/SystemUserRole.java
@@ -1,5 +1,6 @@
package com.doumee.dao.system.model;
import com.doumee.core.model.LoginUserModel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import com.baomidou.mybatisplus.annotation.IdType;
@@ -16,7 +17,7 @@
 */
@Data
@ApiModel("用户角色关联")
public class SystemUserRole implements Serializable {
public class SystemUserRole extends LoginUserModel implements Serializable {
    @ApiModelProperty(value = "主键", example = "1")
    @TableId(type = IdType.AUTO)
server/visits/dmvisit_admin/src/main/java/com/doumee/cloud/common/PublicCloudController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,334 @@
package com.doumee.cloud.common;
import com.alibaba.fastjson.JSONObject;
import com.doumee.api.BaseController;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.DateUtil;
import com.doumee.core.utils.FtpUtil;
import com.doumee.core.utils.aliyun.ALiYunUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;
/**
 * @author Eva.Caesar Liu
 * @date 2023/02/14 11:14
 */
@Api(tags = "公共上传接口")
@Trace(exclude = true)
@RestController
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/public")
@Slf4j
public class PublicCloudController extends BaseController {
    @Autowired
    private SystemDictDataBiz systemDictDataBiz;
    public static FtpUtil ftp  = null;
    @ApiOperation(value = "上传文件到FTP")
    @RequestMapping(method= RequestMethod.POST,value="/upload")
    @ResponseBody
    public void upload(HttpServletRequest request, HttpServletResponse response, String folder) throws Exception {
//        folder = systemDictDataBiz.queryByCode(Constants.FTP,folder).getCode();
        String prefixPath = systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_RESOURCE_PATH).getCode();
        InputStream is = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        Map<String, Object> context = new HashMap<>();
        try {
            if(ftp == null){
                ftp = new FtpUtil(systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_HOST).getCode(),
                        Integer.parseInt(systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_PORT).getCode()),
                        systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_USERNAME).getCode(),
                        systemDictDataBiz.queryByCode(Constants.FTP,Constants.FTP_PWD).getCode());
            }else{
                ftp.connect();
            }
            CommonsMultipartResolver multipartResovler = new CommonsMultipartResolver();
            if (multipartResovler.isMultipart(request)) {
                MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
                Iterator<String> it = multipartRequest.getFileNames();
                while (it.hasNext()) {
                    MultipartFile file = multipartRequest.getFile(it.next());
                    String originname = file.getOriginalFilename();
                    is = file.getInputStream();
                    String date = DateUtil.getNowShortDate();
                    String fName =  date+"/"+ UUID.randomUUID()+".jpg";
                    String fileName = folder+"/"+fName;
                    boolean r = ftp.uploadInputstream(is,fileName);
                    if(r){
                        context.put("success", true);
                        context.put("code", 200);
                        context.put("errno",0);
                        JSONObject fileJSON = new JSONObject();
//                        fileJSON.put("prefixPath", prefixPath);
//                        fileJSON.put("folder", folder);
                        fileJSON.put("url", prefixPath+fileName);
                        fileJSON.put("imgaddr", fName);
                        fileJSON.put("imgname", fileName);
                        fileJSON.put("originname", originname);
                        context.put("data",fileJSON);
                        context.put("message","请求成功");
                        writerJson(response, context);
                        return;
                    }
                }
            }
        } catch (Exception e) {
            log.error("【上传FTP失败】======================"+e.getMessage());
        }
        context.put("code", 0);
        context.put("message", "上传失败");
        context.put("errno",0);
        writerJson(response, context);
        return;
    }
    public void upload(HttpServletRequest request, HttpServletResponse response, String folder, String bucketName,
                       String access_id, String access_key, String resourcePath, String endpoint) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        Map<String, Object> context = new HashMap<>();
        CommonsMultipartResolver multipartResovler = new CommonsMultipartResolver();
        if (multipartResovler.isMultipart(request)) {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Iterator<String> it = multipartRequest.getFileNames();
            while (it.hasNext()) {
                MultipartFile file = multipartRequest.getFile((String) it.next());// file
                // multipartRequest.getFile((String)
                // it.next());
                if (file != null) {
                    // 1、上传到服务器临时文件夹
                    String uploadFileName = file.getOriginalFilename();
                    String originname = uploadFileName;
                    if (originname.lastIndexOf("/") >= 0) {
                        originname = originname.substring(originname.lastIndexOf("/") + 1);
                    }
                    String nfix = "";// åŽç¼€å
                    if (StringUtils.isNotBlank(uploadFileName)) {
                        nfix = uploadFileName.substring(uploadFileName.lastIndexOf("."));
                    }
                    if (StringUtils.equalsIgnoreCase(nfix, ".exe")) {
                        context.put("code", 4000);
                        context.put("message", "对不起,文件格式\".exe\"上传有误!");
                        return;
                    }
                    if (StringUtils.equalsIgnoreCase(nfix, ".dll")) {
                        context.put("code", 4000);
                        context.put("message", "对不起,文件格式\".dll\"上传有误!");
                        return;
                    }
                    String nowDate = DateUtil.getNowShortDate();// å½“前时间(年月日)
                    String fileName = UUID.randomUUID().toString() + nfix;
                    String tempFileName = nowDate + "/" + fileName;
                    String key = folder + tempFileName;// æ–‡ä»¶å
                    ALiYunUtil obs = new ALiYunUtil(endpoint,access_id, access_key);
                    if (obs.uploadOnlineObject(file.getInputStream(),bucketName, key,null)) {
                        // ç§»åŠ¨æˆåŠŸ,返回文件名
                        // sendSuccessMessage(response, resourcePath+key);
                        context.put("success", true);
                        context.put("code", 200);
                        context.put("errno",0);
                        JSONObject fileJSON = new JSONObject();
                        fileJSON.put("url", resourcePath + key);
                        fileJSON.put("imgaddr", tempFileName);
                        fileJSON.put("imgname", fileName);
                        fileJSON.put("originname", originname);
                        context.put("data",fileJSON);
                        context.put("message","请求成功");
                        writerJson(response, context);
                        return;
                    } else {
                        // ç§»åŠ¨å¤±è´¥
                        context.put("code", 0);
                        context.put("message", "上传失败");
                        writerJson(response, context);
                        return;
                    }
                }
            }
        }
        context.put("code", 0);
        context.put("message", "上传失败");
        context.put("errno",0);
        writerJson(response, context);
        return;
    }
    public static void writerJson(HttpServletResponse response, Object object) {
        response.setContentType("application/json");
        writer(response, JSONObject.toJSONString(object));
    }
    private static void writer(HttpServletResponse response, String str) {
        try {
            StringBuffer result = new StringBuffer();
            //设置页面不缓存
            response.setHeader("Pragma", "No-cache");
            response.setHeader("Cache-Control", "no-cache");
            response.setCharacterEncoding("UTF-8");
            PrintWriter out = null;
            out = response.getWriter();
            out.print(str);
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void uploadFileLocal(HttpServletRequest request, String folder, HttpServletResponse response, String rootPath,String dir) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        CommonsMultipartResolver multipartResovler = new CommonsMultipartResolver();
        Map<String, Object> context = new HashMap<>();
        if (multipartResovler.isMultipart(request)) {
            MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
            Iterator<String> it = multipartRequest.getFileNames();
            while (it.hasNext()) {
                MultipartFile file = multipartRequest.getFile((String) it.next());// file
                // =
                // (CommonsMultipartFile)
                // multipartRequest.getFile((String)
                // it.next());
                if (file != null) {
                    if (file.getSize() > 200 * 1024 * 1024L) {
                        context.put("code", 4000);
                        context.put("message", "上传文件过大");
                        return;
                    }
                    System.out.println(file.getOriginalFilename());
                    if (file.getOriginalFilename() == null) {
                        context.put("code", 4000);
                        context.put("message", "文件名不可为空");
                        return;
                    }
                    /*
                     * if(file.getOriginalFilename().contains(",")||file.getOriginalFilename().
                     * contains(" ")){ sendFailureMessage(response,"文件名称有误,不可含有逗号等特殊字符"); }
                     */
                    String nowDate = DateUtil.getNowShortDate();
                    folder += nowDate + "/";
                    String strDirPath = rootPath + folder;
                    File dirPath = new File(strDirPath);
                    if (!dirPath.exists()) {
                        dirPath.mkdirs();
                    }
                    String uploadFileName = file.getOriginalFilename();
                    String x = UUID.randomUUID().toString().replace("-", "")
                            + uploadFileName.substring(uploadFileName.lastIndexOf("."));
                    String fileName = folder + x;
                    String fileNames = nowDate + "/" + x;
                    uploadFileName = uploadFileName.replace(" ", "");
                    uploadFileName = uploadFileName.replace(",", ",");
                    uploadFileName = uploadFileName.replaceAll(",", "-");
                    System.err.println("R:" + fileName);
                    String fileAndPath = dir + fileName;
                    System.err.println("A:" + fileAndPath);
                    // åˆ¤æ–­å¦‚果临时目录中存在相同名称的文件先删除,在上传
                    File tempFile = new File(rootPath + fileName);
                    if (tempFile.isFile() && tempFile.exists()) {
                        tempFile.getAbsoluteFile().delete();
                    }
                    // ä¸Šä¼ åˆ°æœåŠ¡å™¨ä¸´æ—¶æ–‡ä»¶å¤¹
                    file.transferTo(tempFile);
                    // è½¬ç§»åˆ°FTP服务器
                    String nfix = "";
                    if (null != uploadFileName) {
                        nfix = uploadFileName.substring(uploadFileName.lastIndexOf("."));
                    }
                    if (StringUtils.equalsIgnoreCase(nfix, ".exe")) {
                        context.put("code", 4000);
                        context.put("message", "对不起,文件格式\".exe\"上传有误!");
                        return;
                    }
                    if (StringUtils.equalsIgnoreCase(nfix, ".dll")) {
                        context.put("code", 4000);
                        context.put("message", "对不起,文件格式\".dll\"上传有误!");
                        return;
                    }
                    String remoteName = fileName;
                    String remoteFileName = fileAndPath;
             /*       Map map = new HashMap();
                    map.put("url", remoteFileName);
                    map.put("alt", uploadFileName);
                    map.put("href", remoteFileName);
                    List maps = Arrays.asList(remoteFileName);*/
                    if (true) {
                        // å…³é—­FTP流
                        // ç§»åŠ¨æˆåŠŸ,返回文件名
                        /*context.put("error", 0);
                        context.put("url", remoteFileName);
                        context.put("fullurl", remoteFileName);
                        context.put("fname", uploadFileName);
                        context.put("data", maps);
                        context.put("halfurl", fileNames);*/
                        context.put("success", true);
                        context.put("code", 200);
                        context.put("errno",0);
                        JSONObject fileJSON = new JSONObject();
                        fileJSON.put("url", remoteFileName);
                        fileJSON.put("imgaddr", fileNames);
                        fileJSON.put("imgname", uploadFileName);
                        fileJSON.put("originname", uploadFileName);
                        context.put("data",fileJSON);
                        context.put("message","请求成功");
                        writerJson(response, context);
                        return;
                    } else {
                        // ç§»åŠ¨å¤±è´¥
                        context.put("code", 0);
                        context.put("message", "上传失败");
                        writerJson(response, context);
                    }
                }
                context.put("code", 0);
                context.put("message", "上传失败");
                writerJson(response, context);
                return;
            }
        }
        context.put("code", 0);
        context.put("message", "上传失败");
        writerJson(response, context);
        return;
    }
}
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarBook.java
@@ -31,7 +31,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码")
@@ -40,8 +39,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarParks.java
@@ -31,7 +31,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码")
@@ -40,8 +39,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/CarUseBook.java
@@ -31,7 +31,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -40,8 +39,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Member.java
@@ -33,7 +33,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -42,8 +41,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Parks.java
@@ -32,7 +32,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码")
@@ -41,8 +40,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Platform.java
@@ -31,7 +31,6 @@
    @ApiModelProperty(value = "创建时间")
    @ExcelColumn(name="创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date createDate;
    @ApiModelProperty(value = "更新人编码", example = "1")
@@ -40,8 +39,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")
server/visits/dmvisit_service/src/main/java/com/doumee/dao/business/model/Visits.java
@@ -44,8 +44,7 @@
    @ApiModelProperty(value = "更新时间")
    @ExcelColumn(name="更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date editDate;
      private Date editDate;
    @ApiModelProperty(value = "是否删除0否 1是", example = "1")
    @ExcelColumn(name="是否删除0否 1是")