jiangping
2024-05-09 b62578f8b43f15be89b3d14f463f11aed03e6fb9
最新版本
已添加27个文件
已删除2个文件
已修改7个文件
28135 ■■■■ 文件已修改
admin/package-lock.json 378 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/base/BaseOpera.vue 6 ●●●● 补丁 | 查看 | 原始文档 | 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/views/meeting/api/bookings.js 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/devices.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/home.js 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/notice.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/projects.js 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/roomRecord.js 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/roomTime.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/meeting/api/rooms.js 47 ●●●●● 补丁 | 查看 | 原始文档 | 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/system_gateway/src/main/resources/bootstrap.yml 2 ●●● 补丁 | 查看 | 原始文档 | 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/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('@/') ==-1){
        this.api = require('@/api' + extParams.api)
      }else{
        this.api = require(extParams.api)
      }
      extParams['field.id'] && (this.configData['field.id'] = extParams['field.id'])
    },
    /**
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/views/meeting/api/bookings.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,83 @@
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/views/meeting/api/devices.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
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/views/meeting/api/home.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
import request from '@/utils/request'
// æŸ¥è¯¢
export function home (data) {
  return request.post('/meetingAdmin/cloudService/business/home/home', data, {
    trim: true
  })
}
admin/src/views/meeting/api/notice.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
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/views/meeting/api/projects.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
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/views/meeting/api/roomRecord.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
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/views/meeting/api/roomTime.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,6 @@
import request from '@/utils/request'
// æŸ¥è¯¢
export function findList (data) {
  return request.post('/meetingAdmin/cloudService/business/roomTime/findList', data)
}
admin/src/views/meeting/api/rooms.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,47 @@
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/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 '@/views/meeting/api/rooms'
import { getSystemDictData } from '@/api/system/dictData'
import { fetchTree } from '@/api/system/department'
import { cancelById, bookingsDetail } from '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/projects'
import { findList } from '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/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: '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/rooms'
import { updateById } from '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/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: '@/views/meeting/api/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 '@/views/meeting/api/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: '@/views/meeting/api/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/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: