jiangping
2024-05-20 dc22358d8624d3f5a2c27ee6c27e0bdbfe705fe9
Merge remote-tracking branch 'origin/master'
已添加8个文件
已删除1个文件
已修改16个文件
2240 ■■■■ 文件已修改
admin/package-lock.json 186 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/assets/style/style.scss 161 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/GlobalWindow.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/QueryForm/index.js 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/components/common/QueryForm/queryForm.vue 241 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/application/index.vue 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/approvalConfiguration.vue 194 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/page-components/ReportDetail.vue 422 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/reportRecord.vue 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/business/visitOrigin.vue 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/task/index.vue 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/src/views/task/taskDetail.vue 417 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/vue.config.js 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
h5/App.vue 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/api/business/BookingsController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/ApiController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/MeetingApi.java 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/NoticeApi.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/RoomsApi.java 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/UtilApi.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/BookingsMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/dao/web/response/MeetingListResponse.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/BookingsServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
server/system_service/src/main/java/com/doumee/core/utils/DateUtil.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
admin/package-lock.json
@@ -1876,63 +1876,6 @@
          "integrity": "sha1-/q7SVZc9LndVW4PbwIhRpsY1IPo=",
          "dev": true
        },
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.4",
          "resolved": "https://registry.npmmirror.com/loader-utils/-/loader-utils-2.0.4.tgz",
          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "ssri": {
          "version": "8.0.1",
          "resolved": "https://registry.npm.taobao.org/ssri/download/ssri-8.0.1.tgz?cache=0&sync_timestamp=1617826515595&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fssri%2Fdownload%2Fssri-8.0.1.tgz",
@@ -1940,28 +1883,6 @@
          "dev": true,
          "requires": {
            "minipass": "^3.1.1"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        },
        "vue-loader-v16": {
          "version": "npm:vue-loader@16.8.3",
          "resolved": "https://registry.npmmirror.com/vue-loader/-/vue-loader-16.8.3.tgz",
          "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
          "dev": true,
          "optional": true,
          "requires": {
            "chalk": "^4.1.0",
            "hash-sum": "^2.0.0",
            "loader-utils": "^2.0.0"
          }
        }
      }
@@ -2934,8 +2855,7 @@
    "big.js": {
      "version": "5.2.2",
      "resolved": "https://registry.nlark.com/big.js/download/big.js-5.2.2.tgz?cache=0&sync_timestamp=1620132748267&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fbig.js%2Fdownload%2Fbig.js-5.2.2.tgz",
      "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg=",
      "dev": true
      "integrity": "sha1-ZfCvOC9Xi83HQr2cKB6cstd2gyg="
    },
    "binary-extensions": {
      "version": "2.2.0",
@@ -4606,6 +4526,11 @@
      "integrity": "sha1-LnG/CxGRU9u0zE6I2epaz7UNwFw=",
      "dev": true
    },
    "dayjs": {
      "version": "1.11.11",
      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
      "integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
    },
    "de-indent": {
      "version": "1.0.2",
      "resolved": "https://registry.npm.taobao.org/de-indent/download/de-indent-1.0.2.tgz",
@@ -5136,6 +5061,15 @@
      "resolved": "https://registry.npm.taobao.org/ejs/download/ejs-2.7.4.tgz?cache=0&sync_timestamp=1612643435705&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fejs%2Fdownload%2Fejs-2.7.4.tgz",
      "integrity": "sha1-SGYSh1c9zFPjZsehrlLDoSDuybo=",
      "dev": true
    },
    "el-tree-transfer": {
      "version": "2.4.7",
      "resolved": "https://registry.npmjs.org/el-tree-transfer/-/el-tree-transfer-2.4.7.tgz",
      "integrity": "sha512-wcjQyqzmiJMDhF3qHR1NcqXp27Q65Td1EsMOVkqqOo9Z2mkVC+cGJEu3V4L90x8c1XgEciQL7tMuSjCP7/8G4g==",
      "requires": {
        "lodash": "^4.17.20",
        "wl-core": "^1.1.4"
      }
    },
    "electron-to-chromium": {
      "version": "1.3.728",
@@ -13937,6 +13871,87 @@
        }
      }
    },
    "vue-loader-v16": {
      "version": "npm:vue-loader@16.8.3",
      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.8.3.tgz",
      "integrity": "sha512-7vKN45IxsKxe5GcVCbc2qFU5aWzyiLrYJyUuMz4BQLKctCj/fmCa0w6fGiiQ2cLFetNcek1ppGJQDCup0c1hpA==",
      "dev": true,
      "optional": true,
      "requires": {
        "chalk": "^4.1.0",
        "hash-sum": "^2.0.0",
        "loader-utils": "^2.0.0"
      },
      "dependencies": {
        "ansi-styles": {
          "version": "4.3.0",
          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-convert": "^2.0.1"
          }
        },
        "chalk": {
          "version": "4.1.2",
          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
          "dev": true,
          "optional": true,
          "requires": {
            "ansi-styles": "^4.1.0",
            "supports-color": "^7.1.0"
          }
        },
        "color-convert": {
          "version": "2.0.1",
          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
          "dev": true,
          "optional": true,
          "requires": {
            "color-name": "~1.1.4"
          }
        },
        "color-name": {
          "version": "1.1.4",
          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
          "dev": true,
          "optional": true
        },
        "has-flag": {
          "version": "4.0.0",
          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
          "dev": true,
          "optional": true
        },
        "loader-utils": {
          "version": "2.0.4",
          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
          "dev": true,
          "optional": true,
          "requires": {
            "big.js": "^5.2.2",
            "emojis-list": "^3.0.0",
            "json5": "^2.1.2"
          }
        },
        "supports-color": {
          "version": "7.2.0",
          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
          "dev": true,
          "optional": true,
          "requires": {
            "has-flag": "^4.0.0"
          }
        }
      }
    },
    "vue-property-decorator": {
      "version": "8.5.1",
      "resolved": "https://registry.npmjs.org/vue-property-decorator/-/vue-property-decorator-8.5.1.tgz",
@@ -14737,6 +14752,15 @@
      "resolved": "https://registry.npmmirror.com/wildcard/-/wildcard-1.1.2.tgz",
      "integrity": "sha512-DXukZJxpHA8LuotRwL0pP1+rS6CS7FF2qStDDE1C7DDg2rLud2PXRMuEDYIPhgEezwnlHNL4c+N6MfMTjCGTng=="
    },
    "wl-core": {
      "version": "1.1.9",
      "resolved": "https://registry.npmjs.org/wl-core/-/wl-core-1.1.9.tgz",
      "integrity": "sha512-7L83qEnrVW3YmPVqSwnlagoWJyVq/uSXkCFzND64nwtSdDm7o1RZQWiVgQcEilZxE0qLrRQKmjuAihNT6fWCjA==",
      "requires": {
        "big.js": "^5.2.2",
        "dayjs": "^1.8.25"
      }
    },
    "word-wrap": {
      "version": "1.2.3",
      "resolved": "https://registry.npm.taobao.org/word-wrap/download/word-wrap-1.2.3.tgz",
admin/package.json
@@ -16,6 +16,7 @@
    "axios": "^0.21.1",
    "core-js": "^3.6.5",
    "echarts": "^5.4.3",
    "el-tree-transfer": "^2.4.7",
    "element-tiptap": "^1.27.1",
    "element-ui": "^2.3.6",
    "js-cookie": "^2.2.1",
admin/src/assets/style/style.scss
@@ -20,6 +20,7 @@
    margin: 0;
    overflow: scroll;
    overflow: hidden;
    font-size: 14px;
    scrollbar-width: none; /* firefox */
    -ms-overflow-style: none; /* IE 10+ */
    &::-webkit-scrollbar {
@@ -124,3 +125,163 @@
    top: 1px;
  }
}
.main_app {
  background-color: #fff;
  padding: 30px;
  margin: 0 16px;
}
/** åŸºç¡€é€šç”¨ **/
 // å¤§å° å¤–边距
 .flex1{
  flex: 1;
 }
 .w100{
  width: 100px !important;
 }
 .w120{
  width: 120px !important;
 }
 .w200{
  width: 200px !important;
 }
 .w300{
  width: 300px;
 }
 .w400{
  width: 400px !important;
 }
 .pt5 {
  padding-top: 5px;
}
.pr5 {
  padding-right: 5px;
}
.pb5 {
  padding-bottom: 5px;
}
.mt5 {
  margin-top: 5px;
}
.mr5 {
  margin-right: 5px;
}
.mb5 {
  margin-bottom: 5px;
}
.mb8 {
  margin-bottom: 8px;
}
.ml5 {
  margin-left: 5px;
}
.mt10 {
  margin-top: 10px;
}
.mr10 {
  margin-right: 10px;
}
.mb10 {
  margin-bottom: 10px;
}
.ml10 {
  margin-left: 10px;
}
.mt20 {
  margin-top: 20px;
}
.mr20 {
  margin-right: 20px;
}
.mb20 {
  margin-bottom: 20px;
}
.red{
  color: red !important;
}
.table_btns{
  border-bottom: 1px solid #eee;
  padding-bottom: 10px;
}
.ml20 {
  margin-left: 20px;
}
.mt30 {
  margin-top: 30px;
}
.mr30 {
  margin-right: 30px;
}
.mb30 {
  margin-bottom: 30px;
}
.pr20{
  padding-right: 20px;
}
.ml30 {
  margin-left: 30px;
}
.h24{
  height: 24px;
  line-height: 24px;
}
// flex布局
.df{
  display: flex;
}
.df_ac{
  display: flex;
  align-items: center;
  p {
    margin: 0;
  }
}
.df_sb{
  display: flex;
  justify-content: space-between;
  align-items: center;
}
// æ–‡æœ¬æ ·å¼
.underline{
  text-decoration: underline;
}
.fs12{
  font-size: 12px;
}
.fs_12{
  font-size: 12px;
}
.fs_16{
  font-size: 16px;
}
.fs_18{
  font-size: 18px;
}
.fs_24{
  font-size: 24px;
}
.text{
  color: #333333;
}
.tac{
  text-align: center;
}
admin/src/components/common/GlobalWindow.vue
@@ -21,7 +21,8 @@
    <div v-if="withFooter" class="window__footer">
      <slot name="footer">
        <el-button @click="confirm" :loading="confirmWorking" type="primary">{{text}}</el-button>
        <el-button @click="close">返回</el-button>
        <slot name="btns" />
        <el-button @click="close">{{ backText }}</el-button>
      </slot>
    </div>
  </el-drawer>
@@ -45,6 +46,10 @@
      type: String,
      default: '确定'
    },
    backText: {
      type: String,
      default: '返回'
    },
    // ç¡®è®¤æŒ‰é’®loading状态
    confirmWorking: {
      type: Boolean,
@@ -66,6 +71,7 @@
      this.$emit('confirm')
    },
    close () {
      this.$emit('close')
      this.$emit('update:visible', false)
    }
  }
admin/src/components/common/QueryForm/index.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,3 @@
import QueryForm from './queryForm.vue'
export default QueryForm
admin/src/components/common/QueryForm/queryForm.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,241 @@
<template>
  <div class="doumee-filter">
    <el-form inline label-suffix=":" @submit.native.prevent>
      <template v-for="(item, index) in queryFormConfig.formItems">
        <el-form-item v-if="item.type === 'input' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label">
          <el-input v-model="searchForm[item.filed]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.placeholder ? item.placeholder : '请输入' + item.label" class="w200"
            @change="changeForm(item.filed)" @keyup.enter.native="handlekeyup(item.keyup || false)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'moneySelect' && (showZk || index < listLength)" :key="item.label"
          :label="item.label">
          <el-input v-model="searchForm[item.filedStrt]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.start" style="width: 150px" />
          <div class="date-division-line" style="margin-left: 10px;margin-bottom: 0;">~</div>
          <el-input v-model="searchForm[item.filedEnd]"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.end" style="width: 150px" />
        </el-form-item>
        <el-form-item v-if="item.type === 'select' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label">
          <el-select v-model="searchForm[item.filed]" :filterable="item.filterable || true"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.placeholder ? item.placeholder : '请选择' + item.label" class="w200"
            @change="changeForm(item.filed)">
            <el-option v-for="opt, i in item.options" :key="i" :value="item.valueCode ? opt[item.valueCode] : opt.value"
              :label="item.labelCode ? opt[item.labelCode] : opt.label" />
          </el-select>
        </el-form-item>
        <el-form-item v-if="item.type === 'date' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label || '日期'">
          <el-date-picker v-model="searchForm[item.filed]" type="date" value-format="yyyy-MM-dd" class="w200"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :placeholder="item.placeholder || '请选择日期'" :picker-options="item.pickerOptions || {}"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'daterange' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label || ''">
          <el-date-picker v-model="searchForm[item.filed]" value-format="yyyy-MM-dd" type="daterange"
            range-separator="至"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :start-placeholder="item.start || ''" :end-placeholder="item.end || ''"
            :picker-options="item.pickerOptions || {}" class="w400" @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'timePicker' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label || '选择时间'">
          <el-time-picker v-model="searchForm[item.filed]" is-range range-separator="至" format="HH:mm"
            value-format="HH:mm" start-placeholder="开始时间" end-placeholder="结束时间" placeholder="选择时间范围" class="w400"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'datetimerange' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label || '选择日期'">
          <el-date-picker v-model="searchForm[item.filed]" format="yyyy-MM-dd HH:mm:ss"
            value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange"
            :picker-options="item.pickerOptions || pickerOptions" range-separator="至"
            :clearable="(item.clearable !== null && item.clearable !== undefined && item.clearable !== '') ? item.clearable : true"
            :start-placeholder="item.start || '开始时间'" :end-placeholder="item.end || '结束时间'" class="w400"
            @change="changeForm(item.filed)" />
        </el-form-item>
        <el-form-item v-if="item.type === 'slot' && (showZk || index < listLength)" :key="item.filed"
          :label="item.label">
          <slot :name="item.filed" />
        </el-form-item>
      </template>
      <!-- æ“ä½œ -->
      <el-form-item>
        <el-button type="primary" @click="handleQuery">搜索</el-button>
        <el-button v-if="showQk" @click="clear">重置</el-button>
        <slot name="btns" />
        <template v-if="queryFormConfig.formItems.length > listLength">
          <el-button v-if="!showZk" type="text" @click="zkBtn">展开<i
              class="el-icon-caret-bottom primaryColor" /></el-button>
          <el-button v-if="showZk" type="text" @click="zkBtn">收起<i class="el-icon-caret-top primaryColor" /></el-button>
        </template>
      </el-form-item>
    </el-form>
  </div>
</template>
<script>
export default {
  props: {
    value: {
      type: Object,
      default: () => { }
    },
    showQk: {
      type: Boolean,
      default: true
    },
    listLength: {
      type: Number,
      default: 3
    },
    queryFormConfig: {
      type: Object,
      default: () => { }
    }
  },
  data() {
    return {
      showZk: false,
      pickerOptions: {
        shortcuts: [{
          text: '近7天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 6)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近30天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 29)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近60天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 59)
            picker.$emit('pick', [start, end])
          }
        },
        {
          text: '近90天',
          onClick(picker) {
            const end = new Date()
            const start = new Date()
            start.setTime(end.getTime() - 3600 * 1000 * 24 * 89)
            picker.$emit('pick', [start, end])
          }
        }],
        disabledDate(time) {
          var curDate = new Date(new Date().toLocaleDateString()).getTime()
          var preDate = new Date(curDate + 24 * 60 * 60 * 1000 - 1)
          return time.getTime() > preDate
        }
      }
    }
  },
  emits: ['input', 'handleQuery', 'clear'],
  computed: {
    searchForm: {
      get() {
        return this.value
      },
      set(value) {
        this.$emit('input', value)
      }
    }
  },
  methods: {
    handleQuery() {
      this.$emit('handleQuery')
    },
    handlekeyup(pd) {
      if (pd) {
        this.$emit('handleQuery')
      }
    },
    changeForm(filed) {
      this.$emit('changeForm', filed)
    },
    zkBtn() {
      this.showZk = !this.showZk
      this.$emit('zkBtn', this.zk)
    },
    clear() {
      this.$emit('clear')
    }
  }
}
</script>
<style lang="scss" scoped>
.doumee-filter {
  display: flex;
  align-items: center;
  position: relative;
  flex-wrap: wrap;
  align-items: center;
  background-color: #fff;
  border-bottom: 10px solid #f7f8f9;
  margin: 0 -30px;
  padding: 0 0 0 30px;
  .el-input,
  .el-select {
    width: 200px;
    margin-right: 20px;
    margin-bottom: 20px;
    height: 36px;
    .el-input__inner {
      /* color: $textColor; */
      padding: 0 16px;
    }
  }
  .el-date-editor {
    width: 200px;
    margin-right: 20px;
    margin-bottom: 20px;
    .el-input__inner {
      padding-left: 30px;
    }
  }
  .el-button {
    margin-bottom: 20px;
  }
  .el-form-item {
    margin-bottom: 20px;
    margin-right: 20px;
    .el-input,
    .el-select,
    .el-date-editor {
      margin-right: 0;
    }
    .el-input,
    .el-select,
    .el-date-editor,
    .el-button {
      margin-bottom: 0;
    }
  }
}
</style>
admin/src/views/application/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,79 @@
<template>
  <div class="main_app">
    <div class="one_level" v-for="(menu, i) in dataList" :key="i">
      <div class="title">
        {{ menu.name }}
      </div>
      <div class="list">
        <div class="item" @click="handleClick(item)" v-for="item in menu.children" :key="item.name">
          <img src="" alt="" class="icon" />
          <div class="name">{{ item.name }}</div>
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data () {
    return {
      dataList: [
        {
          name: '业务中心',
          children: [
            { name: '用车申请记录', url: '' },
            { name: '会议室预约记录', url: '' },
            { name: '随患随手拍记录', url: '' },
            { name: '用餐记录', url: '' },
            { name: 'dddd', url: '' }
          ]
        },
        {
          name: '月台中心',
          children: [
            { name: '用车申请记录', url: '' },
            { name: '会议室预约记录', url: '' },
            { name: '随患随手拍记录', url: '' },
            { name: '用餐记录', url: '' },
            { name: 'dddd', url: '' }
          ]
        }
      ]
    }
  },
  methods: {
    handleClick (item) {
      console.log(item)
    }
  }
}
</script>
<style lang="scss" scoped>
.one_level {
  padding: 16px 0;
  .title {
    font-size: 16px;
    font-weight: 600;
    border-bottom: 1px solid #cccccc;
    padding: 12px 16px;
    margin-bottom: 20px;
  }
  .list {
    display: flex;
    flex-wrap: wrap;
    .item {
      display: flex;
      align-items: center;
      margin-bottom: 20px;
      width: 25%;
      .icon {
        width: 60px;
        height: 60px;
        margin-right: 12px;
      }
    }
  }
}
</style>
admin/src/views/business/approvalConfiguration.vue
@@ -1,11 +1,17 @@
<template>
    <TableLayout>
        <template v-slot:table-wrap>
      <el-tabs v-model="activeName">
        <el-tab-pane label="普通访客" name="first"></el-tab-pane>
        <el-tab-pane label="施工访客" name="second"></el-tab-pane>
      </el-tabs>
            <div class="config">
                <div class="config_list">
                    <div class="config_list_head">
                        <span>配置流程</span>
                        <el-button style="background: #435EBE;" type="primary">发布</el-button>
            <el-button style="background: #435ebe" type="primary"
              >发布</el-button
            >
                    </div>
                    <div class="config_list_list">
                        <div class="item">
@@ -20,25 +26,43 @@
                                </div>
                            </div>
                        </div>
                        <div :class="item.active ? 'item yellow active' : 'item yellow'" v-for="(item, index) in list" :key="index" @click="seleItem(index)">
            <div
              :class="item.active ? 'item yellow active' : 'item yellow'"
              v-for="(item, index) in list"
              :key="index"
              @click="seleItem(index)"
            >
                            <div class="item_label">审批人</div>
                            <div class="item_child" style="cursor: pointer;">
                                <img class="item_child_right" src="@/assets/images/ar_more@2x.png" />
              <div class="item_child" style="cursor: pointer">
                <img
                  class="item_child_right"
                  src="@/assets/images/ar_more@2x.png"
                />
                                <div class="item_child_label">被访人</div>
                                <div class="item_child_val">访客</div>
                            </div>
                            <div class="item_down">
                                <img class="item_down_add" v-if="list.length - 1 === index" src="@/assets/images/peizhi_add@2x.png" @click.stop="add" />
                <!-- <img
                  class="item_down_add"
                  v-if="list.length - 1 === index"
                  src="@/assets/images/peizhi_add@2x.png"
                  @click.stop="add"
                /> -->
                                <div class="item_down_x">
                                    <img src="@/assets/images/peizhi_ar@2x.png" alt="" />
                                </div>
                            </div>
                        </div>
                        <div class="item blue" style="height: 81px;">
            <div class="item blue" style="height: 81px">
                            <div class="item_label">抄送人</div>
                            <div class="item_child" style="cursor: pointer;height: 40px;">
                                <img class="item_child_right" src="@/assets/images/ar_more@2x.png" />
                                <div class="item_child_val" style="margin-top: 3px;">请设置抄送人</div>
              <div class="item_child" style="cursor: pointer; height: 40px">
                <img
                  class="item_child_right"
                  src="@/assets/images/ar_more@2x.png"
                />
                <div class="item_child_val" style="margin-top: 3px">
                  è¯·è®¾ç½®æŠ„送人
                </div>
                            </div>
                            <div class="item_down">
                                <div class="item_down_x">
@@ -53,9 +77,7 @@
                </div>
                <div class="config_data">
                    <div class="config_data_item">
                        <div class="config_data_item_label">
                            é€‰æ‹©è¯¥èŠ‚ç‚¹çš„å®¡æ‰¹äºº
                        </div>
            <div class="config_data_item_label">选择该节点的审批人</div>
                        <el-radio-group v-model="radio">
                            <el-radio :label="0">被访人</el-radio>
                            <el-radio :label="1">指定人员</el-radio>
@@ -71,7 +93,7 @@
                                    <span>栓子哥</span>
                                    <i class="el-icon-close"></i>
                                </div>
                                <span class="add">+添加</span>
                <span class="add" @click="selStaff">+添加</span>
                            </div>
                        </div>
                        <div class="config_data_item_reviewed" v-if="radio === 2">
@@ -80,15 +102,22 @@
                            </div>
                            <div class="config_data_item_reviewed_r">
                                <span>被访人的</span>
                                <el-select v-model="value" placeholder="请选择" style="margin: 0 20px 0 10px;">
                <el-select
                  v-model="value"
                  placeholder="请选择"
                  style="margin: 0 20px 0 10px"
                >
                                    <el-option
                                        v-for="item in options"
                                        :key="item.value"
                                        :label="item.label"
                                        :value="item.value">
                    :value="item.value"
                  >
                                    </el-option>
                                </el-select>
                                <el-checkbox v-model="checked">找不到主管时,由上级主管代审核</el-checkbox>
                <el-checkbox v-model="checked"
                  >找不到主管时,由上级主管代审核</el-checkbox
                >
                            </div>
                        </div>
                    </div>
@@ -97,35 +126,75 @@
                            å®¡æ‰¹æ–¹å¼
                            <span>审批人为多个时,采用的审批方式</span>
                        </div>
                        <el-radio-group v-model="radio1" style="display: flex; flex-direction: column;">
                            <el-radio :label="0" style="margin-bottom: 20px;">或签(其中一名审批人同意或拒绝即可)</el-radio>
            <el-radio-group
              v-model="radio1"
              style="display: flex; flex-direction: column"
            >
              <el-radio :label="0" style="margin-bottom: 20px"
                >或签(其中一名审批人同意或拒绝即可)</el-radio
              >
                            <el-radio :label="1">会签(所有审批人都同意才可通过)</el-radio>
                        </el-radio-group>
                    </div>
                    <div class="config_data_item" v-if="radio === 2">
                        <div class="config_data_item_label">
                            å®¡æ‰¹äººä¸ºç©ºæ—¶
                        </div>
                        <el-checkbox-group v-model="checkList" style="display: flex; flex-direction: column;">
                            <el-checkbox label="复选框 A" style="margin-bottom: 20px;"></el-checkbox>
                            <el-checkbox label="复选框 B" style="margin-bottom: 20px;"></el-checkbox>
            <div class="config_data_item_label">审批人为空时</div>
            <el-checkbox-group
              v-model="checkList"
              style="display: flex; flex-direction: column"
            >
              <el-checkbox
                label="复选框 A"
                style="margin-bottom: 20px"
              ></el-checkbox>
              <el-checkbox
                label="复选框 B"
                style="margin-bottom: 20px"
              ></el-checkbox>
                            <el-checkbox label="复选框 C"></el-checkbox>
                        </el-checkbox-group>
                    </div>
                    <div class="config_data_submit" v-if="radio !== 0">
                        <el-button style="background: #435EBE;" type="primary">保持配置项</el-button>
            <el-button style="background: #435ebe" type="primary"
              >保持配置项</el-button
            >
                    </div>
                </div>
            </div>
        </template>
    <!--  -->
    <el-dialog title="选择员工" :visible.sync="isShowTransfer" width="800px">
      <tree-transfer
        v-model="param.menuIds"
        :title="['未选', '已选']"
        :from_data="fromData"
        :to_data="selData"
        :defaultProps="{ label: 'label' }"
        mode="transfer"
        height="500px"
        filter
        openAll
        ref="treeTransfer"
      >
      </tree-transfer>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowTransfer = false">取 æ¶ˆ</el-button>
        <el-button type="primary" @click="isShowTransfer = false"
          >ç¡® å®š</el-button
        >
      </span>
    </el-dialog>
    </TableLayout>
</template>
<script>
import TableLayout from '@/layouts/TableLayout'
import treeTransfer from 'el-tree-transfer'
export default {
  name: 'config',
  components: { TableLayout },
  components: {
    TableLayout,
    treeTransfer
  },
  data () {
    return {
      list: [
@@ -139,7 +208,47 @@
      radio: 0,
      radio1: 0,
      checked: '',
      checkList: []
      checkList: [],
      param: {},
      activeName: 'first',
      isShowTransfer: false,
      fromData: [
        {
          id: '1',
          pid: 0,
          label: '一级 1',
          children: [
            {
              id: '1-1',
              pid: '1',
              label: '二级 1-1',
              disabled: true,
              children: []
            },
            {
              id: '1-2',
              pid: '1',
              label: '二级 1-2',
              children: [
                {
                  id: '1-2-1',
                  pid: '1-2',
                  children: [],
                  label: '二级 1-2-1'
                },
                {
                  id: '1-2-2',
                  pid: '1-2',
                  children: [],
                  label: '二级 1-2-2'
                }
              ]
            }
          ]
        }
      ],
      selData: []
    }
  },
  methods: {
@@ -148,6 +257,9 @@
        name: '',
        active: false
      })
    },
    selStaff() {
      this.isShowTransfer = true
    },
    seleItem (i) {
      this.list.forEach((item, index) => {
@@ -174,8 +286,8 @@
            border-radius: 2px;
            padding: 20px;
            box-sizing: border-box;
            border: 1px solid #EEEEEE;
            background: #F7F7F7;
    border: 1px solid #eeeeee;
    background: #f7f7f7;
            .config_list_head {
                width: 100%;
                height: 40px;
@@ -201,18 +313,18 @@
                    width: 0;
                }
                .active {
                    border: 2px solid #E84A08 !important;
        border: 2px solid #e84a08 !important;
                }
                .yellow {
                    background: #EE8921 !important;
        background: #ee8921 !important;
                }
                .blue {
                    background: #435EBE !important;
        background: #435ebe !important;
                }
                .footer {
                    width: 106px;
                    height: 41px;
                    background: #FFFFFF;
        background: #ffffff;
                    box-shadow: 0px 0px 8px 0px rgba(0,0,0,0.1);
                    border-radius: 25px;
                    display: flex;
@@ -227,7 +339,7 @@
                .item {
                    width: 200px;
                    height: 102px;
                    background: #7999D9;
        background: #7999d9;
                    box-shadow: 0 0 8px 0 rgba(0,0,0,0.1);
                    border-radius: 4px;
                    padding: 4px;
@@ -259,7 +371,7 @@
                        .item_down_x {
                            width: 1px;
                            height: 60px;
                            background: #B2B2B2;
            background: #b2b2b2;
                            position: relative;
                            img {
                                position: absolute;
@@ -277,14 +389,14 @@
                        align-items: center;
                        font-size: 15px;
                        font-weight: 400;
                        color: #FFFFFF;
          color: #ffffff;
                    }
                    .item_child {
                        width: 100%;
                        height: 61px;
                        padding: 10px;
                        box-sizing: border-box;
                        background: #FFFFFF;
          background: #ffffff;
                        border-radius: 4px;
                        position: relative;
                        .item_child_right {
@@ -375,20 +487,20 @@
                        padding: 12px;
                        box-sizing: border-box;
                        border-radius: 2px;
                        border: 1px solid #DFE2E8;
          border: 1px solid #dfe2e8;
                        display: flex;
                        align-items: flex-start;
                        flex-wrap: wrap;
                        .add {
                            font-size: 12px;
                            font-weight: 400;
                            color: #435EBE;
            color: #435ebe;
                            cursor: pointer;
                            margin-top: 3px;
                        }
                        .config_data_item_reviewed_content_item {
                            padding: 3px 5px;
                            background: #F4F7FC;
            background: #f4f7fc;
                            border-radius: 2px;
                            box-sizing: border-box;
                            margin-right: 10px;
@@ -399,7 +511,7 @@
                                color: #333333;
                            }
                            i {
                                color: #949BA2;
              color: #949ba2;
                                margin-left: 10px;
                                cursor: pointer;
                            }
admin/src/views/business/page-components/ReportDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,422 @@
<template>
  <GlobalWindow
    :title="title"
    text="同意"
    backText="拒绝"
    :visible.sync="isShowModal"
    @confirm="confirm"
    @close="reject"
  >
    <div class="modal_wrap">
      <div class="modal_content">
        <div class="header">
          <div class="left">
            <div class="h1">访客预约</div>
            <div class="time">提交时间:</div>
          </div>
          <div class="right">待审核</div>
        </div>
        <div class="info">
          <div class="title">访客报备详情</div>
          <div class="list">
            <div class="item">
              <div class="label">被访人</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">拜访时间</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">入园车辆</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">来访单位</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">联系人</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">随车人数</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">来访事由</div>
              <div class="value"></div>
            </div>
          </div>
        </div>
        <div class="table_info">
          <div class="title">访客信息</div>
          <el-table :data="detail.datalist" border fit>
            <el-table-column label="姓名" prop="" min-width="150">
              <template slot-scope="{ row }">
                <div class="name_wrap">
                  <image src="" class="avatar" mode="" />
                  <div class="content">
                    <div class="line">
                      <div class="name">李东</div>
                      <div class="tag">申请人</div>
                    </div>
                    <div class="line placeholder9">1888888</div>
                  </div>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="性别" prop="" min-width="40" />
            <el-table-column label="证件类型" prop="" min-width="80" />
            <el-table-column label="证件号码" prop="" min-width="120" />
            <el-table-column label="公司名称" prop="" min-width="120" />
            <el-table-column label="人脸照片" prop="" min-width="80">
              <template slot-scope="{ row }">
                <el-image :src="row.url" :preview-src-list="[row.url]">
                </el-image>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
      <div class="side">
        <div class="side_title">审批流程</div>
        <div class="list">
          <div class="item">
            <div class="separate"></div>
            <div class="info">
              <i class="el-icon-success icon"></i>
              <img src="" class="avatar" alt="" />
              <div class="content">
                <div class="line">
                  <div class="name">刘某刘某</div>
                  <div class="time">2020-02-02 12:20</div>
                </div>
                <div class="line">
                  <div class="company">中国移动有限公司</div>
                </div>
              </div>
            </div>
          </div>
          <div class="item">
            <!-- <div v-if="" class="separate"></div> -->
            <div class="info">
              <i class="el-icon-success icon"></i>
              <img src="" class="avatar" alt="" />
              <div class="content">
                <div class="line">
                  <div class="name">刘某刘某</div>
                  <div class="time">2020-02-02 12:20</div>
                </div>
                <div class="line">
                  <div class="company">
                    ä¸­å›½ç§»åŠ¨æœ‰é™å…¬å¸( <span class="status">已同意</span> )
                  </div>
                </div>
              </div>
            </div>
            <div class="remark">提交约好的</div>
          </div>
        </div>
      </div>
    </div>
    <!--  -->
    <template #btns>
      <el-button type="primary" plain @click="handleTransfer">转交</el-button>
    </template>
    <!--  åŒæ„/拒绝 -->
    <el-dialog
      append-to-body
      :title="apprTitle"
      :visible.sync="isShowAppr"
      width="480px"
    >
      <el-input
        type="textarea"
        :placeholder="apprTitle + '说明,非必填'"
        :rows="4"
        v-model="param.explain"
      />
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowAppr = false">取消</el-button>
        <el-button type="primary" @click="isShowAppr = false">确定</el-button>
      </span>
    </el-dialog>
    <!-- é𐿂£ -->
    <el-dialog
      append-to-body
      title="隐患"
      :visible.sync="isShowProblem"
      width="480px"
    >
      <el-form :model="param" :rules="rules" ref="ruleForm" label-width="100px">
        <el-form-item label="退回时间">
          <el-date-picker
            class="w300"
            value-format="yyyy-MM-dd"
            type="date"
            placeholder="选择日期"
            v-model="param.date"
          />
        </el-form-item>
        <el-form-item label="整改前">
          <div class="df_ac">
            <img src="@/assets/avatar/man.png" />
            <el-upload
              class="avatar-uploader"
              action="https://jsonplaceholder.typicode.com/posts/"
              :show-file-list="false"
              :on-success="handleAvatarSuccess"
              :before-upload="beforeAvatarUpload"
            >
              <img v-if="param.url" :src="param.url" class="avatar" />
              <div v-else class="upload_box">
                <el-icon class="el-icon-plus icon" />
                <div class="text">图片/视频</div>
              </div>
            </el-upload>
          </div>
        </el-form-item>
        <el-form-item label="退回说明">
          <el-input
            type="textarea"
            placeholder="请填写说明"
            :rows="4"
            v-model="param.explain"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowProblem = false">取消</el-button>
        <el-button type="primary" @click="isShowProblem = false"
          >确定</el-button
        >
      </span>
    </el-dialog>
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  components: { GlobalWindow },
  data() {
    return {
      title: '访客预约详情',
      isShowModal: false,
      detail: {
        datalist: [{}]
      },
      isShowAppr: false,
      apprTitle: '同意',
      param: {},
      isShowProblem: false,
      rules: {}
    }
  },
  methods: {
    confirm() {
      console.log('--')
    },
    handleTransfer() {
      this.isShowProblem = true
    },
    reject() { },
    handleAvatarSuccess() { },
    beforeAvatarUpload() { }
  }
}
</script>
<style lang="scss" scoped>
.upload_box {
  width: 84px;
  height: 84px;
  border-radius: 4px;
  background-color: #f7f7f7;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #999999;
  border: 1px solid #e4e4e4;
  .icon {
    font-size: 24px;
  }
  .text {
    font-size: 12px;
  }
}
.modal_wrap {
  display: flex;
  height: 100%;
  .modal_content {
    flex: 1;
    padding: 0px 30px;
    border-radius: 8px;
    overflow: hidden;
    height: 100%;
    .title {
      font-weight: 600;
      font-size: 18px;
      color: #333333;
      margin-bottom: 20px;
      margin-top: 30px;
    }
    .info {
      .list {
        display: flex;
        flex-wrap: wrap;
        .item {
          display: flex;
          width: 40%;
          margin-bottom: 20px;
          &:nth-of-type(2n) {
            width: 60%;
          }
          .label {
            color: #888888;
            width: 68px;
          }
          .value {
            color: #111111;
          }
        }
      }
    }
    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 20px 30px;
      margin: 0 -30px;
      border-radius: 8px 8px 0 0;
      background: linear-gradient(to right, #f2f6fe, #cadffa);
      .h1 {
        font-weight: 600;
        font-size: 22px;
        color: #111111;
        margin-bottom: 8px;
      }
      .time {
        font-size: 14px;
        color: #999999;
      }
      .right {
        height: 40px;
        font-size: 16px;
        color: #ffffff;
        line-height: 40px;
        padding: 0 20px;
        background: #207ff7;
        box-shadow: 4px 4px 0px 0px rgba(32, 127, 247, 0.16);
        border-radius: 16px 0px 16px 0px;
      }
    }
    .table_info {
      .name_wrap {
        display: flex;
        align-items: center;
        .avatar {
          width: 40px;
          height: 40px;
          border-radius: 50%;
          margin-right: 12px;
        }
        .content {
          .line {
            display: flex;
          }
          .tag {
            color: #b2cbf9;
            border: 1px solid #b2cbf9;
            padding: 0px 4px;
            border-radius: 4px;
            margin-left: 6px;
          }
        }
      }
    }
  }
  .side {
    height: 100%;
    width: 420px;
    background: #ffffff;
    border-left: 20px solid #f7f7f7;
    .list {
      .item {
        padding: 8px 0;
        position: relative;
        .separate {
          position: absolute;
          border-left: 2px dashed #cccccc;
          left: 51px;
          height: calc(100% - 24px);
          top: 46px;
        }
        .info {
          display: flex;
          align-items: center;
          margin-left: 40px;
          .icon {
            position: relative;
            z-index: 11;
            color: #53b76f;
            font-size: 24px;
          }
          .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            margin: 0 12px 0 16px;
            border: 1px solid;
          }
          .content {
            flex: 1;
            .line {
              display: flex;
              justify-content: space-between;
              align-content: center;
              margin-bottom: 6px;
              .name {
                font-weight: 600;
                font-size: 16px;
                color: #111111;
              }
              .time {
                color: #888888;
              }
              .company {
                font-size: 13px;
                color: #888888;
                .status {
                  color: #00ba67;
                }
              }
            }
          }
        }
        .remark {
          background: #f7f7f7;
          border-radius: 4px;
          padding: 13px 15px;
          color: #666666;
          margin-left: 120px;
        }
      }
    }
  }
}
</style>
admin/src/views/business/reportRecord.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,85 @@
<template>
  <div class="main_app">
    <QueryForm v-model="filters" :query-form-config="queryFormConfig" @handleQuery="getList(1)" @clear="clear" />
    <el-table v-loading="loading" :data="list" stripe row-key="id" default-expand-all>
      <el-table-column prop="" label="入园车辆" min-width="100" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="公司名称" min-width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="联系人信息" min-width="100" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="手机号" min-width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="被访人" min-width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="拜访时间" min-width="120" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" label="拜访事由" min-width="80" show-overflow-tooltip></el-table-column>
      <el-table-column prop="" fixed="right" label="状态" min-width="100"></el-table-column>
      <el-table-column label="操作" width="230" fixed="right">
        <template slot-scope="{row}">
          <el-button type="text" @click="handleDetail(row)" v-permissions="['business:company:update']">查看详情</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination @size-change="handleSizeChange" @current-change="getList" :pagination="pagination" />
    <ReportDetail v-if="isShowDetail" ref="DetailRef" />
  </div>
</template>
<script>
import Pagination from '@/components/common/Pagination'
import QueryForm from '@/components/common/QueryForm'
import ReportDetail from './page-components/ReportDetail.vue'
export default {
  components: {
    ReportDetail,
    QueryForm,
    Pagination
  },
  data () {
    return {
      isShowDetail: false,
      activeTab: '0',
      filters: {},
      queryFormConfig: {
        formItems: [
          {
            filed: 'idCard',
            type: 'input',
            label: '车牌号'
          },
          {
            filed: 'name',
            type: 'input',
            label: '公司名称'
          }
        ],
        online: true
      },
      loading: false,
      sorting: false,
      searchForm: {
        // type: 1
      },
      pagination: {
        capacity: 10,
        page: 1
      },
      list: [{}],
      total: 0
    }
  },
  methods: {
    handleDetail () {
      this.isShowDetail = true
      this.$nextTick(() => {
        this.$refs.DetailRef.isShowModal = true
      })
    },
    getList (page) {},
    clear () { },
    handleSizeChange (capacity) {
      this.pagination.capacity = capacity
    }
  }
}
</script>
<style lang="scss" scoped>
</style>
admin/src/views/business/visitOrigin.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,105 @@
<template>
  <div class="main_app">
    <div class="table_btns">
      <el-button icon="el-icon-plus" @click="handleEdit()" type="primary"
        >新建</el-button
      >
    </div>
    <el-table v-loading="loading" :data="list" stripe>
      <el-table-column
        prop="name"
        label="拜访事由"
        min-width="100"
      ></el-table-column>
      <el-table-column
        prop="name"
        label="排序码"
        min-width="80"
      ></el-table-column>
      <el-table-column label="操作" width="230" fixed="right">
        <!-- v-permissions="['business:company:update']" -->
        <template slot-scope="{ row }">
          <el-button type="text" icon="el-icon-edit" @click="handleEdit(row)"
            >编辑</el-button
          >
          <el-button
            type="text"
            icon="el-icon-delete"
            @click="handleDetail(row)"
            class="red"
            >删除</el-button
          >
        </template>
      </el-table-column>
    </el-table>
    <pagination
      @size-change="handleSizeChange"
      @current-change="getList"
      :pagination="pagination"
    />
    <!--  -->
    <el-dialog title="拜访事由" :visible.sync="isShowEdit" width="480px">
      <el-form :model="param" :rules="rules" ref="ruleForm" label-width="100px">
        <el-form-item label="拜访事由">
          <el-input type="text" placeholder="请输入" v-model="param.explain" />
        </el-form-item>
        <el-form-item label="排序码">
          <el-input
            type="text"
            placeholder="请输入"
            oninput="value=value.replace(/^(0+)|[^\d]+/g, '').slice(0, 6)"
            v-model="param.sortNum"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowEdit = false">取消</el-button>
        <el-button type="primary" @click="handleSub">确定</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import Pagination from '@/components/common/Pagination'
export default {
  components: {
    Pagination
  },
  data() {
    return {
      loading: false,
      pagination: {
        capacity: 10,
        page: 1
      },
      list: [{}],
      total: 0,
      isShowEdit: false,
      param: {},
      rules: {}
    }
  },
  methods: {
    handleSub() {
      this.$refs.ruleForm.validate((valid) => {
        if (valid) {
          alert('submit!')
        }
      })
    },
    handleEdit() {
      this.isShowEdit = true
    },
    getList(page) { },
    clear() { },
    handleSizeChange(capacity) {
      this.pagination.capacity = capacity
    }
  }
}
</script>
<style>
</style>
admin/src/views/task/index.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,86 @@
<template>
  <div class="main_app">
    <QueryForm v-model="filters" :query-form-config="queryFormConfig" @handleQuery="getList(1)" @clear="clear" />
    <!--  -->
    <el-tabs v-model="activeTab">
      <el-tab-pane label="待处理" name="0"></el-tab-pane>
      <el-tab-pane label="已处理" name="1"></el-tab-pane>
      <el-tab-pane label="我发起的" name="2"></el-tab-pane>
      <el-tab-pane label="抄送我的" name="3"></el-tab-pane>
    </el-tabs>
    <el-table v-loading="loading" :data="list" stripe row-key="id" default-expand-all>
      <el-table-column prop="name" label="任务类型" min-width="100"></el-table-column>
      <el-table-column prop="name" label="提交人" min-width="80"></el-table-column>
      <el-table-column prop="companyNamePath" label="提交时间" min-width="100"></el-table-column>
      <el-table-column label="操作" width="230" fixed="right">
        <template slot-scope="{row}">
          <el-button type="text" @click="handleDetail(row)" v-permissions="['business:company:update']">查看详情</el-button>
        </template>
      </el-table-column>
    </el-table>
    <pagination @size-change="handleSizeChange" @current-change="getList" :pagination="pagination" />
    <TaskDetail v-if="isShowDetail" ref="DetailRef" />
  </div>
</template>
<script>
import Pagination from '@/components/common/Pagination'
import QueryForm from '@/components/common/QueryForm'
import TaskDetail from './taskDetail.vue'
export default {
  components: {
    TaskDetail,
    QueryForm,
    Pagination
  },
  data () {
    return {
      isShowDetail: false,
      activeTab: '0',
      filters: {},
      queryFormConfig: {
        formItems: [
          {
            filed: 'taskType',
            type: 'select',
            label: '任务类型',
            options: []
          },
          {
            filed: 'status',
            type: 'daterange',
            label: ''
          }
        ],
        online: true
      },
      loading: false,
      sorting: false,
      searchForm: {
        // type: 1
      },
      pagination: {
        capacity: 10,
        page: 1
      },
      list: [{}],
      total: 0
    }
  },
  methods: {
    handleDetail () {
      this.isShowDetail = true
      this.$nextTick(() => {
        this.$refs.DetailRef.isShowModal = true
      })
    },
    getList (page) { },
    clear () { },
    handleSizeChange (capacity) {
      this.pagination.capacity = capacity
    }
  }
}
</script>
<style scoped lang="scss"></style>
admin/src/views/task/taskDetail.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,417 @@
<template>
  <GlobalWindow
    :title="title"
    text="同意"
    backText="拒绝"
    :visible.sync="isShowModal"
    @confirm="confirm"
    @close="reject"
  >
    <div class="modal_wrap">
      <div class="modal_content">
        <div class="header">
          <div class="left">
            <div class="h1">访客预约</div>
            <div class="time">提交时间:</div>
          </div>
          <div class="right">待审核</div>
        </div>
        <div class="info">
          <div class="title">访客预约信息</div>
          <div class="list">
            <div class="item">
              <div class="label">被访人</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">来访时间</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">来访事由</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">随行车辆</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">施工人员</div>
              <div class="value"></div>
            </div>
            <div class="item">
              <div class="label">施工内容</div>
              <div class="value"></div>
            </div>
          </div>
        </div>
        <div class="table_info">
          <div class="title">访客信息</div>
          <el-table :data="detail.datalist" border fit>
            <el-table-column label="姓名" prop="" min-width="150">
              <template slot-scope="{ row }">
                <div class="name_wrap">
                  <image src="" class="avatar" mode="" />
                  <div class="content">
                    <div class="line">
                      <div class="name">李东</div>
                      <div class="tag">申请人</div>
                    </div>
                    <div class="line placeholder9">1888888</div>
                  </div>
                </div>
              </template>
            </el-table-column>
            <el-table-column label="性别" prop="" min-width="40" />
            <el-table-column label="证件类型" prop="" min-width="80" />
            <el-table-column label="证件号码" prop="" min-width="120" />
            <el-table-column label="公司名称" prop="" min-width="120" />
            <el-table-column label="人脸照片" prop="" min-width="80">
              <template slot-scope="{ row }">
                <el-image :src="row.url" :preview-src-list="[row.url]"> </el-image>
              </template>
            </el-table-column>
          </el-table>
        </div>
      </div>
      <div class="side">
        <div class="side_title">审批流程</div>
        <div class="list">
          <div class="item">
            <div class="separate"></div>
            <div class="info">
              <i class="el-icon-success icon"></i>
              <img src="" class="avatar" alt="" />
              <div class="content">
                <div class="line">
                  <div class="name">刘某刘某</div>
                  <div class="time">2020-02-02 12:20</div>
                </div>
                <div class="line">
                  <div class="company">中国移动有限公司</div>
                </div>
              </div>
            </div>
          </div>
          <div class="item">
            <!-- <div v-if="" class="separate"></div> -->
            <div class="info">
              <i class="el-icon-success icon"></i>
              <img src="" class="avatar" alt="" />
              <div class="content">
                <div class="line">
                  <div class="name">刘某刘某</div>
                  <div class="time">2020-02-02 12:20</div>
                </div>
                <div class="line">
                  <div class="company">
                    ä¸­å›½ç§»åŠ¨æœ‰é™å…¬å¸( <span class="status">已同意</span> )
                  </div>
                </div>
              </div>
            </div>
            <div class="remark">提交约好的</div>
          </div>
        </div>
      </div>
    </div>
    <!--  -->
    <template #btns>
      <el-button type="primary" plain @click="handleTransfer">转交</el-button>
    </template>
    <!--  åŒæ„/拒绝 -->
    <el-dialog
      append-to-body
      :title="apprTitle"
      :visible.sync="isShowAppr"
      width="480px"
    >
      <el-input
        type="textarea"
        :placeholder="apprTitle + '说明,非必填'"
        :rows="4"
        v-model="param.explain"
      />
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowAppr = false">取消</el-button>
        <el-button type="primary" @click="isShowAppr = false">确定</el-button>
      </span>
    </el-dialog>
    <!-- é𐿂£ -->
    <el-dialog
      append-to-body
      title="隐患"
      :visible.sync="isShowProblem"
      width="480px"
    >
      <el-form :model="param" :rules="rules" ref="ruleForm" label-width="100px">
        <el-form-item label="退回时间">
          <el-date-picker
            class="w300"
            value-format="yyyy-MM-dd"
            type="date"
            placeholder="选择日期"
            v-model="param.date"
          />
        </el-form-item>
        <el-form-item label="整改前">
          <div class="df_ac">
            <img src="@/assets/avatar/man.png" />
            <el-upload
              class="avatar-uploader"
              action="https://jsonplaceholder.typicode.com/posts/"
              :show-file-list="false"
              :on-success="handleAvatarSuccess"
              :before-upload="beforeAvatarUpload"
            >
              <img v-if="param.url" :src="param.url" class="avatar" />
              <div v-else class="upload_box">
                <el-icon class="el-icon-plus icon" />
                <div class="text">图片/视频</div>
              </div>
            </el-upload>
          </div>
        </el-form-item>
        <el-form-item label="退回说明">
          <el-input
            type="textarea"
            placeholder="请填写说明"
            :rows="4"
            v-model="param.explain"
          />
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="isShowProblem = false">取消</el-button>
        <el-button type="primary" @click="isShowProblem = false"
          >确定</el-button
        >
      </span>
    </el-dialog>
  </GlobalWindow>
</template>
<script>
import GlobalWindow from '@/components/common/GlobalWindow'
export default {
  components: { GlobalWindow },
  data() {
    return {
      title: '访客预约详情',
      isShowModal: false,
      detail: {
        datalist: [{}]
      },
      isShowAppr: false,
      apprTitle: '同意',
      param: {},
      isShowProblem: false,
      rules: {}
    }
  },
  methods: {
    confirm() {
      console.log('--')
    },
    handleTransfer() {
      this.isShowProblem = true
    },
    reject() { },
    handleAvatarSuccess() { },
    beforeAvatarUpload() { }
  }
}
</script>
<style lang="scss" scoped>
.upload_box {
  width: 84px;
  height: 84px;
  border-radius: 4px;
  background-color: #f7f7f7;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #999999;
  border: 1px solid #e4e4e4;
  .icon {
    font-size: 24px;
  }
  .text {
    font-size: 12px;
  }
}
.modal_wrap {
  display: flex;
  height: 100%;
  .modal_content {
    flex: 1;
    padding: 0px 30px;
    border-radius: 8px;
    overflow: hidden;
    height: 100%;
    .title {
      font-weight: 600;
      font-size: 18px;
      color: #333333;
      margin-bottom: 20px;
      margin-top: 30px;
    }
    .info {
      .list {
        display: flex;
        flex-wrap: wrap;
        .item {
          display: flex;
          width: 40%;
          margin-bottom: 20px;
          &:nth-of-type(2n) {
            width: 60%;
          }
          .label {
            color: #888888;
            width: 68px;
          }
          .value {
            color: #111111;
          }
        }
      }
    }
    .header {
      display: flex;
      justify-content: space-between;
      align-items: center;
      padding: 20px 30px;
      margin: 0 -30px;
      border-radius: 8px 8px 0 0;
      background: linear-gradient(to right, #f2f6fe, #cadffa);
      .h1 {
        font-weight: 600;
        font-size: 22px;
        color: #111111;
        margin-bottom: 8px;
      }
      .time {
        font-size: 14px;
        color: #999999;
      }
      .right {
        height: 40px;
        font-size: 16px;
        color: #ffffff;
        line-height: 40px;
        padding: 0 20px;
        background: #207ff7;
        box-shadow: 4px 4px 0px 0px rgba(32, 127, 247, 0.16);
        border-radius: 16px 0px 16px 0px;
      }
    }
    .table_info {
      .name_wrap {
        display: flex;
        align-items: center;
        .avatar {
          width: 40px;
          height: 40px;
          border-radius: 50%;
          margin-right: 12px;
        }
        .content {
          .line {
            display: flex;
          }
          .tag {
            color: #b2cbf9;
            border: 1px solid #b2cbf9;
            padding: 0px 4px;
            border-radius: 4px;
            margin-left: 6px;
          }
        }
      }
    }
  }
  .side {
    height: 100%;
    width: 420px;
    background: #ffffff;
    border-left: 20px solid #f7f7f7;
    .list {
      .item {
        padding: 8px 0;
        position: relative;
        .separate {
          position: absolute;
          border-left: 2px dashed #cccccc;
          left: 51px;
          height: calc(100% - 24px);
          top: 46px;
        }
        .info {
          display: flex;
          align-items: center;
          margin-left: 40px;
          .icon {
            position: relative;
            z-index: 11;
            color: #53b76f;
            font-size: 24px;
          }
          .avatar {
            width: 40px;
            height: 40px;
            border-radius: 50%;
            margin: 0 12px 0 16px;
            border: 1px solid;
          }
          .content {
            flex: 1;
            .line {
              display: flex;
              justify-content: space-between;
              align-content: center;
              margin-bottom: 6px;
              .name {
                font-weight: 600;
                font-size: 16px;
                color: #111111;
              }
              .time {
                color: #888888;
              }
              .company {
                font-size: 13px;
                color: #888888;
                .status {
                  color: #00ba67;
                }
              }
            }
          }
        }
        .remark {
          background: #f7f7f7;
          border-radius: 4px;
          padding: 13px 15px;
          color: #666666;
          margin-left: 120px;
        }
      }
    }
  }
}
</style>
admin/vue.config.js
@@ -1,5 +1,10 @@
// è¯¦ç»†é…ç½®è¯·å‚考https://cli.vuejs.org/zh/config/#vue-config-js
// const outputDir = process.env.VUE_APP_CONTEXT_PATH.substring(1, process.env.VUE_APP_CONTEXT_PATH.length - 1)
const path = require('path')
function resolve (dir) {
  return path.join(__dirname, dir)
}
module.exports = {
  publicPath: process.env.VUE_APP_CONTEXT_PATH,
  outputDir: 'admin',
@@ -17,5 +22,14 @@
        }
      }
    }
  },
  configureWebpack: {
    // provide the app's title in webpack's name field, so that
    // it can be accessed in index.html to inject the correct title.
    resolve: {
      alias: {
        '@': resolve('src')
      }
    }
  }
}
h5/App.vue
@@ -177,14 +177,20 @@
    margin: 0;
    display: flex;
}
input{
    font-size: 30rpx
}
textarea {
    box-sizing: border-box;
    background-color: #f7f7f7;
    font-size: 28rpx;
    color: #333333;
    padding: 24rpx;
    // background-color: #f7f7f7;
    font-size: 30rpx !important;
    padding: 0;
    border-radius: 8rpx;
    color: #333333 !important;
}
.u-textarea{
    padding: 0 !important;
    color: #333333 !important;
}
.df_ac {
server/meeting/meeting_admin/src/main/java/com/doumee/api/business/BookingsController.java
@@ -87,8 +87,7 @@
    @PostMapping("/updateById")
    @RequiresPermissions("business:bookings:update")
    public ApiResponse updateById(@RequestBody Bookings bookings) {
        LoginUserInfo user = getLoginUser(null);
        bookings.setCreator(user.getId());
        bookings.setLoginUserInfo(getLoginUser(null));
        bookingsService.updateById(bookings);
        return ApiResponse.success(null);
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/ApiController.java
ÎļþÒÑɾ³ý
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/MeetingApi.java
@@ -1,10 +1,13 @@
package com.doumee.cloud.web;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.doumee.api.BaseController;
import com.doumee.config.Jwt.JwtTokenUtil;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.DateUtil;
import com.doumee.core.utils.QrCodeUtils;
import com.doumee.dao.business.model.Bookings;
@@ -38,9 +41,9 @@
@Api(tags = "2、预定会议业务")
@Trace(exclude = true)
@RestController
@RequestMapping("/web/meeting")
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/web/meeting")
@Slf4j
public class MeetingApi extends ApiController{
public class MeetingApi extends BaseController {
    @Autowired
    private BookingsService bookingsService;
@@ -52,13 +55,14 @@
    @ApiOperation(value = "当月会议表", notes = "当月会议表")
    @GetMapping("/monthMeeting")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "yearMonth", value = "年月  yyyy-MM", required = true)
    })
    public ApiResponse<List<MonthDataResponse>> monthDay(@RequestParam String yearMonth) {
    public ApiResponse<List<MonthDataResponse>> monthDay(@RequestParam String yearMonth
            ,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
        List<String> dataList = DateUtil.getDayByMonth(yearMonth);
        List<MonthDataResponse> monthDataResponseList = new ArrayList<>();
        List<Bookings> bookings = bookingsService.getMyBookings(getMemberId(),yearMonth);
        List<Bookings> bookings = bookingsService.getMyBookings(user.getId(),yearMonth);
        for (String str:dataList) {
            MonthDataResponse  monthDataResponse = new MonthDataResponse();
            monthDataResponse.setWeekMsg(DateUtil.getWeek(DateUtil.StringToDate(str,"yyyy-MM-dd")).getChineseName());
@@ -72,11 +76,10 @@
    @ApiOperation("我的会议列表")
    @PostMapping("/myMeetingPage")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<IPage<MeetingListResponse>> myMeetingPage(@RequestBody PageWrap<MeetingPageRequest> pageWrap) {
        pageWrap.getModel().setUserId(getMemberId());
    public ApiResponse<IPage<MeetingListResponse>> myMeetingPage(@RequestBody PageWrap<MeetingPageRequest> pageWrap
            ,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
        pageWrap.getModel().setUserId(user.getId());
        IPage<MeetingListResponse> page = bookingsService.getMyMeetingPage(pageWrap);
        return ApiResponse.success("查询成功",page);
    }
@@ -85,7 +88,6 @@
    @ApiOperation("会议详情")
    @GetMapping("/meetingDetail")
    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议主键", required = true),
    })
    public ApiResponse<MeetingDetailResponse> meetingDetail(@RequestParam Integer id) {
@@ -93,7 +95,7 @@
    }
    @ApiOperation("获取会议开门二维码")
   /* @ApiOperation("获取会议开门二维码")
    @GetMapping("/getQrCode")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
@@ -116,7 +118,7 @@
        response.setContentType("image/jpeg");
        String content =bookingsService.getQrCode(id,memberId);
        QrCodeUtils.encode(content,null, response.getOutputStream(), true);
    }
    }*/
/*
    @LoginRequired
@@ -134,23 +136,21 @@
    @ApiOperation("会议预约")
    @PostMapping("/reservationMeeting")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<Integer> reservationMeeting(@RequestBody BookingsRequest bookingsRequest) {
        bookingsRequest.setCreator(getMemberId());
        bookingsRequest.setEditor(getMemberId());
    public ApiResponse<Integer> reservationMeeting(@RequestBody BookingsRequest bookingsRequest ,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
        bookingsRequest.setCreator(user.getId());
        bookingsRequest.setEditor(user.getId());
        return ApiResponse.success("操作成功",bookingsService.reservationMeeting(bookingsRequest));
    }
    @ApiOperation("取消会议预约")
    @GetMapping("/reservationCancel")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议主键", required = true),
    })
    public ApiResponse reservationCancel(@RequestParam Integer id) {
        bookingsService.reservationCancel(id,getMemberId());
    public ApiResponse reservationCancel(@RequestParam Integer id,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
        bookingsService.reservationCancel(id,user.getId());
        return ApiResponse.success("操作成功");
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/NoticeApi.java
@@ -1,7 +1,9 @@
package com.doumee.cloud.web;
import com.doumee.api.BaseController;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageData;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
@@ -16,9 +18,9 @@
@Api(tags = "消息通知信业务")
@Trace(exclude = true)
@RestController
@RequestMapping("/web/notice")
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/web/notice")
@Slf4j
public class NoticeApi extends ApiController{
public class NoticeApi extends BaseController {
    @Autowired
    private NoticesService noticeService;
@@ -31,8 +33,10 @@
     */
    @ApiOperation(value = "查询用户通知", notes = "小程序端")
    @PostMapping("/findNoticePage")
    public ApiResponse<PageData<Notices>> findNoticePage(@RequestBody PageWrap<Notices> pageWrap){
        pageWrap.getModel().setUserId(getMemberId());
    public ApiResponse<PageData<Notices>> findNoticePage(@RequestBody PageWrap<Notices> pageWrap
            ,@RequestHeader(Constants.HEADER_USER_TOKEN) String token){
        LoginUserInfo user = getLoginUser(token);
        pageWrap.getModel().setUserId(user.getId());
        return ApiResponse.success("查询成功",noticeService.findPage(pageWrap));
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/RoomsApi.java
@@ -1,10 +1,13 @@
package com.doumee.cloud.web;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.doumee.api.BaseController;
import com.doumee.config.Jwt.JwtTokenUtil;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.model.LoginUserInfo;
import com.doumee.core.model.PageWrap;
import com.doumee.core.utils.Constants;
import com.doumee.core.utils.QrCodeUtils;
import com.doumee.dao.business.model.RoomTime;
import com.doumee.dao.web.request.RoomTimeRequest;
@@ -33,9 +36,9 @@
@Api(tags = "3、会议室业务")
@Trace(exclude = true)
@RestController
@RequestMapping("/web/rooms")
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/web/rooms")
@Slf4j
public class RoomsApi extends ApiController{
public class RoomsApi extends BaseController {
    @Autowired
    private RoomsService roomsService;
@@ -43,57 +46,48 @@
    @Autowired
    private RoomTimeService roomTimeService;
    @ApiOperation("获取会议室开门二维码")
    @GetMapping("/getQrCode")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议室主键", required = true),
    })
    public ApiResponse<String> getQrCode(@RequestParam Integer id) {
        return ApiResponse.success("查询成功", roomsService.getQrCode(id,getMemberId()));
    }
//    @ApiOperation("获取会议室开门二维码")
//    @GetMapping("/getQrCode")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
//            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议室主键", required = true),
//    })
//    public ApiResponse<String> getQrCode(@RequestParam Integer id) {
//        return ApiResponse.success("查询成功", roomsService.getQrCode(id,getMemberId()));
//    }
    @ApiOperation("获取会议室开门二维码-图片流")
    @GetMapping("/getQrCodeImg")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议室主键", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public void getQrCodeImg(@RequestParam Integer id,@RequestParam String token, HttpServletResponse response) throws  Exception {
        Integer memberId = JwtTokenUtil.getJwtPayLoad(token).getMemberId();
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        String content =roomsService.getQrCode(id,memberId);
        QrCodeUtils.encode(content,null, response.getOutputStream(), true);
    }
//    @ApiOperation("获取会议室开门二维码-图片流")
//    @GetMapping("/getQrCodeImg")
//    @ApiImplicitParams({
//            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "id", value = "会议室主键", required = true),
//            @ApiImplicitParam(paramType = "query", dataType = "String", name = "token", value = "用户token值", required = true),
//    })
//    public void getQrCodeImg(@RequestParam Integer id,@RequestParam String token, HttpServletResponse response) throws  Exception {
//        Integer memberId = JwtTokenUtil.getJwtPayLoad(token).getMemberId();
//        response.setHeader("Cache-Control", "no-store, no-cache");
//        response.setContentType("image/jpeg");
//        String content =roomsService.getQrCode(id,memberId);
//        QrCodeUtils.encode(content,null, response.getOutputStream(), true);
//    }
    @ApiOperation("会议室列表")
    @GetMapping("/roomsList")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<List<RoomsResponse>> roomsList() {
    public ApiResponse<List<RoomsResponse>> roomsList(@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success("查询成功",roomsService.getRoomsList());
    }
    @ApiOperation("会议室时间开放列表")
    @PostMapping("/getRoomUseTime")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<List<RoomTime>> getRoomUseTime(@RequestBody RoomTimeRequest roomTimeRequest) {
    public ApiResponse<List<RoomTime>> getRoomUseTime(@RequestBody RoomTimeRequest roomTimeRequest,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success("查询成功",roomTimeService.getRoomUseTime(roomTimeRequest));
    }
    @ApiOperation("我的会议室列表")
    @PostMapping("/myRoomsPage")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
    })
    public ApiResponse<IPage<RoomsResponse>> myRoomsPage(@RequestBody PageWrap<RoomsRequest> pageWrap) {
        pageWrap.getModel().setUserId(getMemberId());
    public ApiResponse<IPage<RoomsResponse>> myRoomsPage(@RequestBody PageWrap<RoomsRequest> pageWrap,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        LoginUserInfo user = getLoginUser(token);
        pageWrap.getModel().setUserId(user.getId());
        IPage<RoomsResponse> page = roomsService.getRoomsPage(pageWrap);
        return ApiResponse.success("查询成功",page);
    }
@@ -102,10 +96,9 @@
    @ApiOperation("会议室详情")
    @GetMapping("/getRoomDetail")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "header", dataType = "String", name = "token", value = "用户token值", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Integer", name = "roomId", value = "会议室主键", required = true),
    })
    public ApiResponse<RoomsResponse> getRoomDetail(@RequestParam Integer roomId) {
    public ApiResponse<RoomsResponse> getRoomDetail(@RequestParam Integer roomId,@RequestHeader(Constants.HEADER_USER_TOKEN) String token) {
        return ApiResponse.success("查询成功",roomsService.getRoomDetail(roomId));
    }
server/meeting/meeting_admin/src/main/java/com/doumee/cloud/web/UtilApi.java
@@ -1,8 +1,10 @@
package com.doumee.cloud.web;
import com.doumee.api.BaseController;
import com.doumee.biz.system.SystemDictDataBiz;
import com.doumee.core.annotation.trace.Trace;
import com.doumee.core.model.ApiResponse;
import com.doumee.core.utils.Constants;
import com.doumee.dao.system.model.SystemDictData;
import com.doumee.service.business.UtilService;
import io.swagger.annotations.Api;
@@ -29,9 +31,9 @@
@Api(tags = "99、帮助业务")
@Trace(exclude = true)
@RestController
@RequestMapping("/web/util")
@RequestMapping(Constants.CLOUD_SERVICE_URL_INDEX+"/web/util")
@Slf4j
public class UtilApi extends ApiController{
public class UtilApi extends BaseController {
    @Autowired
    private UtilService utilService;
@@ -78,7 +80,5 @@
        }
    }
}
server/meeting/meeting_service/src/main/java/com/doumee/dao/business/BookingsMapper.java
@@ -22,7 +22,7 @@
    @Select(" select a.id , b.`NAME` as roomName , a.`NAME` as meetingName  ,date_format(a.START_TIME,'%Y-%m-%d') as meetingDate ," +
    @Select(" select a.id , b.`NAME` as roomName , a.`NAME` as meetingName  ,date_format(a.START_TIME,'%Y-%m-%d') as meetingDate , a.START_TIME as startTime, a.status ," +
            " CONCAT(date_format(a.START_TIME,'%H:%i') , ' ~ ',date_format(a.END_TIME,'%H:%i')) as meetingTime,  c.REALNAME as bookingUser ," +
            " CASE  WHEN a.START_TIME > now() and a.`STATUS` = 0  THEN 1  WHEN a.END_TIME < now()  or a.`STATUS` = 1  THEN 3 ELSE 2  END meetingStatus , b.IMGURL as imgUrl " +
            " from meeting_book a inner join meeting_rooms b  on a.ROOM_ID = b.ID  " +
server/meeting/meeting_service/src/main/java/com/doumee/dao/web/response/MeetingListResponse.java
@@ -6,6 +6,7 @@
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
 * Created by IntelliJ IDEA.
@@ -32,6 +33,13 @@
    @ApiModelProperty(value = "会议时间 ( a ~ b)")
    private String meetingTime;
    @ApiModelProperty(value = "会议开始时间",hidden = true)
    private Date startTime;
    @ApiModelProperty(value = "状态 0已预约 1已撤销 ",hidden = true)
    private Integer status;
    @ApiModelProperty(value = "会议预约人")
    private String bookingUser;
@@ -41,7 +49,7 @@
    @ApiModelProperty(value = "前缀")
    private String prefixUrl;
    @ApiModelProperty(value = "会议状态: 1=未开始;2=进行中;3=已结束")
    @ApiModelProperty(value = "会议状态: 1=未开始;2=进行中;3=已结束 ; 4=即将开始; 5=已撤销")
    private Integer meetingStatus;
}
server/meeting/meeting_service/src/main/java/com/doumee/service/business/impl/BookingsServiceImpl.java
@@ -120,7 +120,7 @@
    @Override
    @Transactional(rollbackFor = {BusinessException.class, Exception.class})
    public Integer create(Bookings bookings) {
        LoginUserInfo user = new LoginUserInfo();
        LoginUserInfo user = bookings.getLoginUserInfo();
        user.setId(bookings.getCreator());
        isCreateParamValid(bookings, user);
        bookings.setCreateDate(new Date());
@@ -778,6 +778,18 @@
        String path = systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.FTP_RESOURCE_PATH).getCode() + systemDictDataBiz.queryByCode(MeetConstants.FTP, MeetConstants.PROJECTS).getCode();
        page.getRecords().forEach(i -> {
            i.setPrefixUrl(path);
            if(i.getMeetingStatus().equals(Constants.ZERO)){
                if(i.getStatus()==Constants.ONE){
                    i.setMeetingStatus(5);
                }else{
                    //开始前5分钟 å¤§äºŽå½“前时间 åˆ™æ˜¾ç¤ºå³å°†å¼€å§‹
                    if(DateUtil.afterMinutesDate(i.getStartTime(),-5).getTime()>System.currentTimeMillis()){
                        i.setMeetingStatus(4);
                    }
                }
            }
        });
        return page;
    }
server/system_service/src/main/java/com/doumee/core/utils/DateUtil.java
@@ -2849,9 +2849,9 @@
    public static void main(String[] args) {
        try {
            Date date = getISO8601DateByStr("2024-04-15T07:46:36.014+08:00");
            Date date1 = getISO8601DateByStr("2024-06-14T08:46:36.014+08:00");
            System.out.println(daysBetweenDates11(date1,date)+1);
//            Date date = getISO8601DateByStr("2024-04-15T07:46:36.014+08:00");
//            Date date1 = getISO8601DateByStr("2024-06-14T08:46:36.014+08:00");
            System.out.println(DateUtil.afterMinutesDate(-5));
        } catch (Exception ex) {
            ex.printStackTrace();
@@ -3108,6 +3108,18 @@
    }
    /**
     * X åˆ†é’ŸåŽæ—¶é—´
     * @param minutes
     * @return
     */
    public static Date afterMinutesDate(Date date,Integer minutes){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE,minutes);
        return cal.getTime();
    }
    /**
     * LocalDateTime to date
     * @param now
     * @return