Browse Source

基础设置

MOKASZ\lw12420 5 years ago
parent
commit
dda4f29b08
67 changed files with 7116 additions and 31 deletions
  1. 195 19
      src/assets/style/common.scss
  2. 50 0
      src/components/DictTag/index.vue
  3. 191 0
      src/components/FileUpload/index.vue
  4. 212 0
      src/components/Pagination/index.vue
  5. 87 0
      src/components/RightToolbar/index.vue
  6. 2 2
      src/components/layout/SideBar.vue
  7. 21 5
      src/main.js
  8. 3 3
      src/network/api/api-base.js
  9. 18 0
      src/network/api/basicSetting/label/basicSettingLabel.js
  10. 18 0
      src/network/api/basicSetting/label/basicSettingLabelType.js
  11. 21 0
      src/network/api/basicSetting/product/basicSettingProduct.js
  12. 21 0
      src/network/api/basicSetting/product/basicSettingProductSource.js
  13. 22 0
      src/network/api/basicSetting/product/basicSettingProductType.js
  14. 24 0
      src/network/api/basicSetting/project/basicSettingProject.js
  15. 70 0
      src/network/api/job/job.js
  16. 26 0
      src/network/api/job/jobLog.js
  17. 52 0
      src/network/api/system/dict/data.js
  18. 60 0
      src/network/api/system/dict/type.js
  19. 26 0
      src/network/api/system/operlog.js
  20. 6 0
      src/network/api/user.js
  21. 64 0
      src/router/index.js
  22. 6 0
      src/utils/errorCode.js
  23. 119 0
      src/utils/request.js
  24. 199 0
      src/utils/ruoyi.js
  25. 58 0
      src/utils/scroll-to.js
  26. 117 0
      src/views/basicSetting/label/basicSettingLabel/BasicSettingLabelMain.vue
  27. 195 0
      src/views/basicSetting/label/basicSettingLabel/OptionDialog.vue
  28. 84 0
      src/views/basicSetting/label/basicSettingLabel/Search.vue
  29. 3 0
      src/views/basicSetting/label/basicSettingLabel/index.js
  30. 30 0
      src/views/basicSetting/label/basicSettingLabel/object.js
  31. 280 0
      src/views/basicSetting/label/basicSettingLabelType/BasicSettingLabelTypeMain.vue
  32. 171 0
      src/views/basicSetting/label/basicSettingLabelType/OptionDialog.vue
  33. 68 0
      src/views/basicSetting/label/basicSettingLabelType/Search.vue
  34. 3 0
      src/views/basicSetting/label/basicSettingLabelType/index.js
  35. 32 0
      src/views/basicSetting/label/basicSettingLabelType/object.js
  36. 261 0
      src/views/basicSetting/product/item/BasicSettingProductMain.vue
  37. 235 0
      src/views/basicSetting/product/item/OptOptionDialog.vue
  38. 310 0
      src/views/basicSetting/product/item/OptionDialog.vue
  39. 207 0
      src/views/basicSetting/product/item/Search.vue
  40. 3 0
      src/views/basicSetting/product/item/index.js
  41. 66 0
      src/views/basicSetting/product/item/object.js
  42. 150 0
      src/views/basicSetting/product/source/BasicSettingProductSourceMain.vue
  43. 165 0
      src/views/basicSetting/product/source/OptionDialog.vue
  44. 89 0
      src/views/basicSetting/product/source/Search.vue
  45. 3 0
      src/views/basicSetting/product/source/index.js
  46. 45 0
      src/views/basicSetting/product/source/object.js
  47. 146 0
      src/views/basicSetting/product/type/BasicSettingProductTypeMain.vue
  48. 117 0
      src/views/basicSetting/product/type/OptionDialog.vue
  49. 51 0
      src/views/basicSetting/product/type/Search.vue
  50. 3 0
      src/views/basicSetting/product/type/index.js
  51. 25 0
      src/views/basicSetting/product/type/object.js
  52. 142 0
      src/views/basicSetting/project/BasicSettingProjectMain.vue
  53. 290 0
      src/views/basicSetting/project/OptionDialog.vue
  54. 97 0
      src/views/basicSetting/project/Search.vue
  55. 3 0
      src/views/basicSetting/project/index.js
  56. 48 0
      src/views/basicSetting/project/object.js
  57. 422 0
      src/views/dict/data.vue
  58. 391 0
      src/views/dict/index.vue
  59. 0 0
      src/views/dictOld/DictMain.vue
  60. 0 0
      src/views/dictOld/OptionDialog.vue
  61. 0 0
      src/views/dictOld/Search.vue
  62. 0 0
      src/views/dictOld/index.js
  63. 0 0
      src/views/dictOld/object.js
  64. 605 0
      src/views/job/index.vue
  65. 343 0
      src/views/job/log.vue
  66. 342 0
      src/views/operlog/index.vue
  67. 3 2
      vue.config.js

+ 195 - 19
src/assets/style/common.scss

@@ -1,8 +1,179 @@
+.height-200 {
+  height: 200px;
+}
+
+.height-50 {
+  height: 50px;
+}
+
+.height-70 {
+  height: 70px;
+}
+
+.height-20 {
+  height: 20px;
+}
+
+.relative {
+  position: relative;
+  height: 100%;
+  background: rgba(0, 0, 0, 0.007);
+}
+
+.justify-center {
+  display: flex;
+  justify-content: center;
+}
+.justify-left {
+  display: flex;
+}
+.justify-end {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.align-center {
+  display: flex;
+  align-items: center;
+}
+.align-end {
+  display: flex;
+  align-items: flex-end;
+}
+
+.justify-between {
+  display: flex;
+  justify-content: space-between;
+}
+
+// padding
+.pl-10 {
+  padding-left: 10px !important;
+}
+
+.pl-20 {
+  padding-left: 20px !important;
+}
+
+.pr-10 {
+  padding-right: 10px !important;
+}
+
+.pr-20 {
+  padding-right: 20px !important;
+}
+
+.pt-10 {
+  padding-top: 10px !important;
+}
+
+.pt-20 {
+  padding-top: 20px !important;
+}
+
+.pb-10 {
+  padding-bottom: 10px !important;
+}
+
+.pb-20 {
+  padding-bottom: 20px !important;
+}
+
+// margin
+.mt-10 {
+  margin-top: 10px !important;
+}
+
+.mt-20 {
+  margin-top: 20px !important;
+}
+
+.mt-40 {
+  margin-top: 40px !important;
+}
+
+.mb-10 {
+  margin-bottom: 10px !important;
+}
+
+.mb-20 {
+  margin-bottom: 20px !important;
+}
+
+.ml-5 {
+  margin-left: 5px !important;
+}
+
+.ml-10 {
+  margin-left: 10px !important;
+}
+
+.ml-20 {
+  margin-left: 20px !important;
+}
+
+.ml-100 {
+  margin-left: 100px !important;
+}
+
+.mr-10 {
+  margin-right: 10px !important;
+}
+
+.mr-5 {
+  margin-right: 5px !important;
+}
+
+.mr-20 {
+  margin-right: 20px !important;
+}
+
+.mt-16 {
+  margin-top: 16px !important;
+}
+
+.mb-16 {
+  margin-bottom: 16px !important;
+}
+
+.ml-16 {
+  margin-left: 16px !important;
+}
+
+.mr-16 {
+  margin-right: 16px !important;
+}
+
+.w-100 {
+  width: 100px !important;
+}
+
+.w-120 {
+  width: 120px !important;
+}
+
+.w-180 {
+  width: 180px !important;
+}
+
+.w-200 {
+  width: 200px !important;
+}
+
+.w-220 {
+  width: 220px !important;
+}
+
+.w-300 {
+  width: 300px !important;
+}
+
 body {
 body {
   padding: 0;
   padding: 0;
   margin: 0;
   margin: 0;
-  background-color: #EFEFF4;
-  font-family: "PingFang SC","Helvetica Neue",Helvetica,"Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;
+  background-color: #efeff4;
+  font-family: "PingFang SC", "Helvetica Neue", Helvetica, "Hiragino Sans GB",
+    "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
 }
 }
 
 
 #app {
 #app {
@@ -41,18 +212,17 @@ body {
 .list-table-delete {
 .list-table-delete {
   white-space: nowrap;
   white-space: nowrap;
   .icon-delete-warning {
   .icon-delete-warning {
-    color: #FF8023;
+    color: #ff8023;
   }
   }
 }
 }
 
 
-
 // 表格状态样式
 // 表格状态样式
 .status-text {
 .status-text {
   color: #d9d9d9;
   color: #d9d9d9;
   font-size: 14px;
   font-size: 14px;
   cursor: pointer;
   cursor: pointer;
   &:before {
   &:before {
-    content: '';
+    content: "";
     width: 4px;
     width: 4px;
     height: 4px;
     height: 4px;
     margin-right: 8px;
     margin-right: 8px;
@@ -63,9 +233,9 @@ body {
     top: -2px;
     top: -2px;
   }
   }
   &.status-progress {
   &.status-progress {
-    color: #4C88F6;
+    color: #4c88f6;
     &:before {
     &:before {
-      background-color: #4C88F6;
+      background-color: #4c88f6;
     }
     }
   }
   }
   &.status-success {
   &.status-success {
@@ -75,9 +245,9 @@ body {
     }
     }
   }
   }
   &.status-danger {
   &.status-danger {
-    color: #FB4444;
+    color: #fb4444;
     &:before {
     &:before {
-      background-color: #FB4444;
+      background-color: #fb4444;
     }
     }
   }
   }
 }
 }
@@ -87,7 +257,8 @@ body {
     //background: #FFFFFF;
     //background: #FFFFFF;
     //box-shadow: 0px 2px 2px 0px rgba(174, 175, 175, 0.2);
     //box-shadow: 0px 2px 2px 0px rgba(174, 175, 175, 0.2);
     //border-radius: 2px;
     //border-radius: 2px;
-    .el-input-number__increase, .el-input-number__decrease {
+    .el-input-number__increase,
+    .el-input-number__decrease {
       background: transparent;
       background: transparent;
     }
     }
     margin-bottom: 20px;
     margin-bottom: 20px;
@@ -96,13 +267,13 @@ body {
     .title {
     .title {
       height: 56px;
       height: 56px;
       line-height: 56px;
       line-height: 56px;
-      border-bottom: solid 1px #EBEBEB;
+      border-bottom: solid 1px #ebebeb;
       box-sizing: border-box;
       box-sizing: border-box;
-      color: #333A3F;
+      color: #333a3f;
       font-size: 18px;
       font-size: 18px;
       font-weight: 600;
       font-weight: 600;
       &:before {
       &:before {
-        content: '';
+        content: "";
         display: inline-block;
         display: inline-block;
         width: 3px;
         width: 3px;
         height: 16px;
         height: 16px;
@@ -116,7 +287,9 @@ body {
     .page-course-content {
     .page-course-content {
       padding: 18px 40px 18px 37px;
       padding: 18px 40px 18px 37px;
       & > .el-form-item {
       & > .el-form-item {
-        .el-input:not(.el-transfer-panel__filter), .el-textarea, .el-select{
+        .el-input:not(.el-transfer-panel__filter),
+        .el-textarea,
+        .el-select {
           width: 400px;
           width: 400px;
         }
         }
         .el-input-number .el-input {
         .el-input-number .el-input {
@@ -128,9 +301,12 @@ body {
         .el-transfer-panel .el-transfer-panel__header {
         .el-transfer-panel .el-transfer-panel__header {
           background: #fff;
           background: #fff;
         }
         }
-        .el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label {
+        .el-transfer-panel
+          .el-transfer-panel__header
+          .el-checkbox
+          .el-checkbox__label {
           font-size: 12px;
           font-size: 12px;
-          color: #1A1414;
+          color: #1a1414;
         }
         }
       }
       }
     }
     }
@@ -141,7 +317,7 @@ body {
       font-size: 12px;
       font-size: 12px;
 
 
       i {
       i {
-        color: #FFB567;
+        color: #ffb567;
       }
       }
 
 
       span {
       span {
@@ -165,7 +341,7 @@ body {
       width: 70px;
       width: 70px;
       height: 36px;
       height: 36px;
       line-height: 36px;
       line-height: 36px;
-      border: solid 1px #E5E9EC;
+      border: solid 1px #e5e9ec;
       box-sizing: border-box;
       box-sizing: border-box;
       color: #333;
       color: #333;
       font-size: 14px;
       font-size: 14px;
@@ -191,7 +367,7 @@ body {
       &:hover {
       &:hover {
         color: $themeColor;
         color: $themeColor;
         border-color: $themeColor;
         border-color: $themeColor;
-        background-color: #ECF1FE;
+        background-color: #ecf1fe;
 
 
         i {
         i {
           background-position: -28px 0;
           background-position: -28px 0;

+ 50 - 0
src/components/DictTag/index.vue

@@ -0,0 +1,50 @@
+<template>
+  <div>
+    <template v-for="(item, index) in options">
+      <template v-if="values.includes(item.dictValue)">
+        <span
+          v-if="item.listClass == 'default' || item.listClass == ''"
+          :key="item.dictValue"
+          :index="index"
+          :class="item.cssClass"
+        >{{ item.dictLabel }}</span>
+        <el-tag
+          v-else
+          :key="item.dictValue"
+          :index="index"
+          :type="item.listClass == 'primary' ? '' : item.listClass"
+          :class="item.cssClass"
+        >
+          {{ item.dictLabel }}
+        </el-tag>
+      </template>
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'DictTag',
+  props: {
+    options: {
+      type: Array,
+      default: null
+    },
+    value: [String, Array]
+  },
+  computed: {
+    values() {
+      if (this.value) {
+        return Array.isArray(this.value) ? this.value : [this.value]
+      } else {
+        return []
+      }
+    }
+  }
+}
+</script>
+<style scoped>
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+</style>

+ 191 - 0
src/components/FileUpload/index.vue

@@ -0,0 +1,191 @@
+<template>
+  <div class="upload-file">
+    <el-upload
+      ref="upload"
+      :action="uploadFileUrl"
+      :before-upload="handleBeforeUpload"
+      :file-list="fileList"
+      :limit="limit"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      :on-success="handleUploadSuccess"
+      :show-file-list="false"
+      :headers="headers"
+      class="upload-file-uploader"
+    >
+      <!-- 上传按钮 -->
+      <el-button size="mini" type="primary">选取文件</el-button>
+      <!-- 上传提示 -->
+      <div v-if="showTip" slot="tip" class="el-upload__tip">
+        请上传
+        <template v-if="fileSize"> 大小不超过 <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+        <template v-if="fileType"> 格式为 <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+        的文件
+      </div>
+    </el-upload>
+
+    <!-- 文件列表 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
+        <el-link :href="file.url" :underline="false" target="_blank">
+          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" type="danger" @click="handleDelete(index)">删除</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'FileUpload',
+  props: {
+    // 值
+    value: [String, Object, Array],
+    // 数量限制
+    limit: {
+      type: Number,
+      default: 5
+    },
+    // 大小限制(MB)
+    fileSize: {
+      type: Number,
+      default: 5
+    },
+    // 文件类型, 例如['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ['doc', 'xls', 'ppt', 'txt', 'pdf']
+    },
+    // 是否显示提示
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      uploadFileUrl: process.env.VUE_APP_BASE_API + '/file/upload', // 上传的图片服务器地址
+
+      fileList: []
+    }
+  },
+  computed: {
+    // 是否显示提示
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize)
+    }
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          let temp = 1
+          // 首先将值转为数组
+          const list = Array.isArray(val) ? val : this.value.split(',')
+          // 然后将数组转为对象数组
+          this.fileList = list.map(item => {
+            if (typeof item === 'string') {
+              item = { name: item, url: item }
+            }
+            item.uid = item.uid || new Date().getTime() + temp++
+            return item
+          })
+        } else {
+          this.fileList = []
+          return []
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  methods: {
+    // 上传前校检格式和大小
+    handleBeforeUpload(file) {
+      // 校检文件类型
+      if (this.fileType) {
+        let fileExtension = ''
+        if (file.name.lastIndexOf('.') > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf('.') + 1)
+        }
+        const isTypeOk = this.fileType.some((type) => {
+          if (file.type.indexOf(type) > -1) return true
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true
+          return false
+        })
+        if (!isTypeOk) {
+          this.$message.error(`文件格式不正确, 请上传${this.fileType.join('/')}格式文件!`)
+          return false
+        }
+      }
+      // 校检文件大小
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize
+        if (!isLt) {
+          this.$message.error(`上传文件大小不能超过 ${this.fileSize} MB!`)
+          return false
+        }
+      }
+      return true
+    },
+    // 文件个数超出
+    handleExceed() {
+      this.$message.error(`上传文件数量不能超过 ${this.limit} 个!`)
+    },
+
+    // 上传成功回调
+    handleUploadSuccess(res, file) {
+      this.$message.success('上传成功')
+      this.fileList.push({ name: res.data.url, url: res.data.url })
+      this.$emit('input', this.listToString(this.fileList))
+    },
+    // 删除文件
+    handleDelete(index) {
+      this.fileList.splice(index, 1)
+      this.$emit('input', this.listToString(this.fileList))
+    },
+    // 获取文件名称
+    getFileName(name) {
+      if (name.lastIndexOf('/') > -1) {
+        return name.slice(name.lastIndexOf('/') + 1).toLowerCase()
+      } else {
+        return ''
+      }
+    },
+    // 对象转成指定字符串分隔
+    listToString(list, separator) {
+      let strs = ''
+      separator = separator || ','
+      for (const i in list) {
+        strs += list[i].url + separator
+      }
+      return strs !== '' ? strs.substr(0, strs.length - 1) : ''
+    }
+  }
+}
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  border: 1px solid #e4e7ed;
+  line-height: 2;
+  margin-bottom: 10px;
+  position: relative;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
+</style>

+ 212 - 0
src/components/Pagination/index.vue

@@ -0,0 +1,212 @@
+<template>
+  <div :class="{'hidden':hidden}" class="clearfix">
+    <el-pagination
+      class="pagination flr"
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :pager-count="pagerCount"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 20, 30, 50]
+      }
+    },
+    // 移动端页码按钮的数量端默认值5
+    pagerCount: {
+      type: Number,
+      default: document.body.clientWidth < 992 ? 5 : 7
+    },
+    layout: {
+      type: String,
+      default: 'total, sizes, prev, pager, next'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(val) {
+      this.$emit('pagination', { page: this.currentPage, limit: val })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(val) {
+      this.$emit('pagination', { page: val, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>
+
+<style lang="scss">
+@import "~@/assets/style/variables.scss";
+
+$pageHeight: 24px;
+.pagination {
+  margin: 30px 0px 30px 100px;
+
+  &.el-pagination .btn-prev,
+  &.el-pagination .btn-next {
+    background-color: transparent;
+    height: $pageHeight;
+    line-height: $pageHeight;
+  }
+
+  &.el-pagination span:not([class*="suffix"]),
+  &.el-pagination button {
+    height: $pageHeight;
+    line-height: $pageHeight;
+  }
+
+  .el-button.jump-btn {
+    width: $pageHeight;
+    height: $pageHeight;
+    background-color: $themeColor;
+    border-radius: 50%;
+    text-align: center;
+    line-height: $pageHeight;
+    padding: 0;
+    color: #fff;
+    margin-left: 15px;
+
+    &:hover {
+      background-color: $themeColor;
+    }
+  }
+
+  &.el-pagination__editor.el-input {
+    width: 56px;
+  }
+
+  .el-pagination__editor.el-input .el-input__inner {
+    height: 32px;
+    border-radius: 16px;
+    border: solid 1px #dcdfe6;
+    background-color: #f8f9fb;
+  }
+
+  .el-pager li {
+    min-width: $pageHeight;
+    height: $pageHeight;
+    margin-right: 13px;
+    line-height: $pageHeight;
+    font-size: 14px;
+    color: #474747;
+    font-weight: 500;
+    transition: all 0.3s;
+    border: solid 1px transparent;
+    box-sizing: border-box;
+
+    &:last-child {
+      margin-right: 0;
+    }
+
+    &:hover {
+      border: solid 1px $themeColor;
+      color: $themeColor;
+      box-sizing: border-box;
+      background-color: #fbfafd;
+    }
+
+    &.active {
+      border: solid 1px $themeColor;
+      color: $themeColor;
+      box-sizing: border-box;
+      border-radius: 2px;
+      background-color: #fbfafd;
+
+      &:hover {
+        border: solid 1px $themeColor;
+        color: $themeColor;
+      }
+    }
+  }
+
+  .el-pagination__jump {
+    margin-left: 10px;
+  }
+
+  &.el-pagination .el-pagination__sizes {
+    margin: 0 5px;
+
+    .el-select .el-input {
+      width: 89px;
+
+      .el-input__inner {
+        height: 24px;
+        border-radius: 2px;
+        border: solid 1px #edecf2;
+      }
+    }
+  }
+}
+</style>

+ 87 - 0
src/components/RightToolbar/index.vue

@@ -0,0 +1,87 @@
+<template>
+  <div class="top-right-btn">
+    <el-row>
+      <el-tooltip class="item" effect="dark" :content="showSearch ? '隐藏搜索' : '显示搜索'" placement="top">
+        <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="刷新" placement="top">
+        <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
+      </el-tooltip>
+      <el-tooltip v-if="columns" class="item" effect="dark" content="显隐列" placement="top">
+        <el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" />
+      </el-tooltip>
+    </el-row>
+    <el-dialog :title="title" :visible.sync="open" append-to-body>
+      <el-transfer
+        v-model="value"
+        :titles="['显示', '隐藏']"
+        :data="columns"
+        @change="dataChange"
+      />
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  name: 'RightToolbar',
+  props: {
+    showSearch: {
+      type: Boolean,
+      default: true
+    },
+    columns: {
+      type: Array
+    }
+  },
+  data() {
+    return {
+      // 显隐数据
+      value: [],
+      // 弹出层标题
+      title: '显示/隐藏',
+      // 是否显示弹出层
+      open: false
+    }
+  },
+  created() {
+    // 显隐列初始默认隐藏列
+    for (const item in this.columns) {
+      if (this.columns[item].visible === false) {
+        this.value.push(parseInt(item))
+      }
+    }
+  },
+  methods: {
+    // 搜索
+    toggleSearch() {
+      this.$emit('update:showSearch', !this.showSearch)
+    },
+    // 刷新
+    refresh() {
+      this.$emit('queryTable')
+    },
+    // 右侧列表元素变化
+    dataChange(data) {
+      for (var item in this.columns) {
+        const key = this.columns[item].key
+        this.columns[item].visible = !data.includes(key)
+      }
+    },
+    // 打开显隐列dialog
+    showColumn() {
+      this.open = true
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+::v-deep .el-transfer__button {
+  border-radius: 50%;
+  padding: 12px;
+  display: block;
+  margin-left: 0px;
+}
+::v-deep .el-transfer__button:first-child {
+  margin-bottom: 10px;
+}
+</style>

+ 2 - 2
src/components/layout/SideBar.vue

@@ -11,12 +11,12 @@
         <span>version: _V1.0 </span>
         <span>version: _V1.0 </span>
       </div>
       </div>
     </div>
     </div>
-
+    <!-- :default-openeds="['/novel-manage', '/tag-manage', '/data-config', '/user-manage', '/sign', '/system', '/project/goods', '/order', '/activity']" -->
     <el-menu
     <el-menu
       :collapse="isCollapse"
       :collapse="isCollapse"
       mode="vertical"
       mode="vertical"
       :default-active="$route.path"
       :default-active="$route.path"
-      :default-openeds="['/novel-manage', '/tag-manage', '/data-config', '/user-manage', '/sign', '/system', '/project/goods', '/order', '/activity']"
+
       router
       router
       class="menu"
       class="menu"
       :style="{ width: isCollapse ? '88px' : '240px' }"
       :style="{ width: isCollapse ? '88px' : '240px' }"

+ 21 - 5
src/main.js

@@ -5,17 +5,33 @@ import store from './store'
 import Element from 'element-ui'
 import Element from 'element-ui'
 
 
 import GlobalPlugin from './common/plugins'
 import GlobalPlugin from './common/plugins'
-
+import { download } from '@/utils/request'
 import '@/assets/style/index.scss'
 import '@/assets/style/index.scss'
-
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from '@/utils/ruoyi'
 import './router/permission'
 import './router/permission'
-
+// 自定义表格工具组件
+import RightToolbar from '@/components/RightToolbar'
+// 字典标签组件
+// 字典标签组件
+import DictTag from '@/components/DictTag'
+import Pagination from '@/components/Pagination/index'
+import { getDicts } from '@/network/api/system/dict/data'
 import has from '@/common/directive/permission/'
 import has from '@/common/directive/permission/'
 
 
 import { hasPerm } from '@/common/utils/has-permission'
 import { hasPerm } from '@/common/utils/has-permission'
-
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.handleTree = handleTree
 Vue.config.productionTip = false
 Vue.config.productionTip = false
-
+Vue.prototype.download = download
+Vue.component('Paginations', Pagination)
+Vue.component('RightToolbar', RightToolbar)
+Vue.component('DictTag', DictTag)
 Vue.directive('has', has)
 Vue.directive('has', has)
 
 
 Vue.prototype.hasPerm = hasPerm
 Vue.prototype.hasPerm = hasPerm

+ 3 - 3
src/network/api/api-base.js

@@ -4,21 +4,21 @@ import service from '@/network/service/service'
  * 获取用户信息
  * 获取用户信息
  */
  */
 export function getUserInfo() {
 export function getUserInfo() {
-  return service.get('/system/admin/getAdminInfo')
+  return service.get('/api/system/admin/getAdminInfo')
 }
 }
 
 
 /**
 /**
  * 获取菜单
  * 获取菜单
  */
  */
 export function getMenuList(params) {
 export function getMenuList(params) {
-  return service.get('/system/admin/getMenuAndRole', { params })
+  return service.get('/api/system/admin/getMenuAndRole', { params })
 }
 }
 
 
 /**
 /**
  * 退出登录
  * 退出登录
  */
  */
 export function logout(params) {
 export function logout(params) {
-  return service.get('/system//admin/logout', { params })
+  return service.get('/api/system/admin/logout', { params })
 }
 }
 
 
 /**
 /**

+ 18 - 0
src/network/api/basicSetting/label/basicSettingLabel.js

@@ -0,0 +1,18 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingLabel/page', data)
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingLabel/save', data)
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingLabel/update', data)
+}
+
+export function DeleteLabel(id) {
+  return service.delete('/api/system/basicSettingLabel/' + id)
+}
+

+ 18 - 0
src/network/api/basicSetting/label/basicSettingLabelType.js

@@ -0,0 +1,18 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingLabelType/page', data)
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingLabelType/save', data)
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingLabelType/update', data)
+}
+
+export function Delete(id) {
+  return service.delete('/api/system/basicSettingLabelType/' + id)
+}
+

+ 21 - 0
src/network/api/basicSetting/product/basicSettingProduct.js

@@ -0,0 +1,21 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingProduct/page', data)
+}
+export function updateBatch(data) {
+  return service.post('/api/system/basicSettingProduct/updateBatch', data)
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingProduct/save', data)
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingProduct/update', data)
+}
+
+export function Delete(id) {
+  return service.delete('/api/system/basicSettingProduct/' + id)
+}
+

+ 21 - 0
src/network/api/basicSetting/product/basicSettingProductSource.js

@@ -0,0 +1,21 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingProductSource/page', data)
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingProductSource/save', data)
+}
+export function getIsUseingData() {
+  return service.get('/api/system/basicSettingProductSource/getIsUseingData')
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingProductSource/update', data)
+}
+
+export function Delete(id) {
+  return service.delete('/api/system/basicSettingProductSource/' + id)
+}
+

+ 22 - 0
src/network/api/basicSetting/product/basicSettingProductType.js

@@ -0,0 +1,22 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingProductType/page', data)
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingProductType/save', data)
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingProductType/update', data)
+}
+
+export function Delete(id) {
+  return service.delete('/api/system/basicSettingProductType/' + id)
+}
+
+export function getAllIsUseing() {
+  return service.get('/api/system/basicSettingProductType/getAllIsUseing')
+}
+

+ 24 - 0
src/network/api/basicSetting/project/basicSettingProject.js

@@ -0,0 +1,24 @@
+import service from '@/network/service/service'
+
+export function Page(data) {
+  return service.post('/api/system/basicSettingProject/page', data)
+}
+export function getProjectForSource() {
+  return service.get('/api/system/basicSettingProject/getProjectForSource')
+}
+export function getProjectForProduct() {
+  return service.get('/api/system/basicSettingProject/getProjectForProduct')
+}
+
+export function Add(data) {
+  return service.post('/api/system/basicSettingProject/save', data)
+}
+
+export function Update(data) {
+  return service.post('/api/system/basicSettingProject/update', data)
+}
+
+export function Delete(id) {
+  return service.delete('/api/system/basicSettingProject/' + id)
+}
+

+ 70 - 0
src/network/api/job/job.js

@@ -0,0 +1,70 @@
+import request from '@/network/service/service'
+
+// 查询定时任务调度列表
+export function listJob(query) {
+  return request({
+    url: '/api/schedule/job/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询定时任务调度详细
+export function getJob(jobId) {
+  return request({
+    url: '/api/schedule/job/' + jobId,
+    method: 'get'
+  })
+}
+
+// 新增定时任务调度
+export function addJob(data) {
+  return request({
+    url: '/api/schedule/job',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改定时任务调度
+export function updateJob(data) {
+  return request({
+    url: '/api/schedule/job',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除定时任务调度
+export function delJob(jobId) {
+  return request({
+    url: '/api/schedule/job/' + jobId,
+    method: 'delete'
+  })
+}
+
+// 任务状态修改
+export function changeJobStatus(jobId, status) {
+  const data = {
+    jobId,
+    status
+  }
+  return request({
+    url: '/api/schedule/job/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 定时任务立即执行一次
+export function runJob(jobId, jobGroup) {
+  const data = {
+    jobId,
+    jobGroup
+  }
+  return request({
+    url: '/api/schedule/job/run',
+    method: 'put',
+    data: data
+  })
+}

+ 26 - 0
src/network/api/job/jobLog.js

@@ -0,0 +1,26 @@
+import request from '@/network/service/service'
+
+// 查询调度日志列表
+export function listJobLog(query) {
+  return request({
+    url: '/api/schedule/job/log/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 删除调度日志
+export function delJobLog(jobLogId) {
+  return request({
+    url: '/api/schedule/job/log/' + jobLogId,
+    method: 'delete'
+  })
+}
+
+// 清空调度日志
+export function cleanJobLog() {
+  return request({
+    url: '/api/schedule/job/log/clean',
+    method: 'delete'
+  })
+}

+ 52 - 0
src/network/api/system/dict/data.js

@@ -0,0 +1,52 @@
+import request from '@/network/service/service'
+
+// 查询字典数据列表
+export function listData(query) {
+  return request({
+    url: '/api/system/dict/data/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询字典数据详细
+export function getData(dictCode) {
+  return request({
+    url: '/api/system/dict/data/' + dictCode,
+    method: 'get'
+  })
+}
+
+// 根据字典类型查询字典数据信息
+export function getDicts(dictType) {
+  return request({
+    url: '/api/system/dict/data/type/' + dictType,
+    method: 'get'
+  })
+}
+
+// 新增字典数据
+export function addData(data) {
+  return request({
+    url: '/api/system/dict/data',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改字典数据
+export function updateData(data) {
+  return request({
+    url: '/api/system/dict/data',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除字典数据
+export function delData(dictCode) {
+  return request({
+    url: '/api/system/dict/data/' + dictCode,
+    method: 'delete'
+  })
+}

+ 60 - 0
src/network/api/system/dict/type.js

@@ -0,0 +1,60 @@
+import request from '@/network/service/service'
+
+// 查询字典类型列表
+export function listType(query) {
+  return request({
+    url: '/api/system/dict/type/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询字典类型详细
+export function getType(dictId) {
+  return request({
+    url: '/api/system/dict/type/' + dictId,
+    method: 'get'
+  })
+}
+
+// 新增字典类型
+export function addType(data) {
+  return request({
+    url: '/api/system/dict/type',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改字典类型
+export function updateType(data) {
+  return request({
+    url: '/api/system/dict/type',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除字典类型
+export function delType(dictId) {
+  return request({
+    url: '/api/system/dict/type/' + dictId,
+    method: 'delete'
+  })
+}
+
+// 刷新字典缓存
+export function refreshCache() {
+  return request({
+    url: '/api/system/dict/type/refreshCache',
+    method: 'delete'
+  })
+}
+
+// 获取字典选择框列表
+export function optionselect() {
+  return request({
+    url: '/api/system/dict/type/optionselect',
+    method: 'get'
+  })
+}

+ 26 - 0
src/network/api/system/operlog.js

@@ -0,0 +1,26 @@
+import request from '@/network/service/service'
+
+// 查询操作日志列表
+export function list(query) {
+  return request({
+    url: '/api/system/operlog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 删除操作日志
+export function delOperlog(operId) {
+  return request({
+    url: '/api/system/operlog/' + operId,
+    method: 'delete'
+  })
+}
+
+// 清空操作日志
+export function cleanOperlog() {
+  return request({
+    url: '/api/system/operlog/clean',
+    method: 'delete'
+  })
+}

+ 6 - 0
src/network/api/user.js

@@ -0,0 +1,6 @@
+import service from '@/network/service/service'
+
+export function getUser() {
+  return service.get('/api/schedule/sysUser/getAllUserForTransfer')
+}
+

+ 64 - 0
src/router/index.js

@@ -31,12 +31,76 @@ const viewRoutes = [{
       import('@/views/redis')
       import('@/views/redis')
   },
   },
   {
   {
+    path: '/productType',
+    name: 'productType',
+    meta: { title: '产品品类' },
+    component: () =>
+      import('@/views/basicSetting/product/type/BasicSettingProductTypeMain')
+  },
+  {
+    path: '/productSource',
+    name: 'productSource',
+    meta: { title: '产品来源' },
+    component: () =>
+      import('@/views/basicSetting/product/source/BasicSettingProductSourceMain')
+  },
+  {
+    path: '/taskScheduling',
+    name: 'taskScheduling',
+    meta: { title: '任务调度' },
+    component: () =>
+      import('@/views/job/index')
+  },
+  {
+    path: '/job-log',
+    name: 'job-log',
+    meta: { title: '任务调度' },
+    component: () =>
+      import('@/views/job/log')
+  },
+  {
+    path: '/projectItemList',
+    name: 'projectItemList',
+    meta: { title: '项目列表' },
+    component: () =>
+      import('@/views/basicSetting/project/BasicSettingProjectMain')
+  },
+  {
+    path: '/productItemList',
+    name: 'productItemList',
+    meta: { title: '产品列表' },
+    component: () =>
+      import('@/views/basicSetting/product/item/BasicSettingProductMain')
+  },
+  {
+    path: '/labelItemList',
+    name: 'labelItemList',
+    meta: { title: '标签别表' },
+    component: () =>
+      import('@/views/basicSetting/label/basicSettingLabelType/BasicSettingLabelTypeMain')
+  },
+  {
+    path: '/optLog',
+    name: 'optLog',
+    meta: { title: '操作日志' },
+    component: () =>
+      import('@/views/operlog/index')
+  },
+  {
     path: '/dict',
     path: '/dict',
     name: 'dict',
     name: 'dict',
     meta: { title: '字典' },
     meta: { title: '字典' },
     component: () =>
     component: () =>
       import('@/views/dict')
       import('@/views/dict')
+  },
+  {
+    path: '/dict-data/:dictId(\\d+)',
+    name: 'dict-data',
+    meta: { title: '字典' },
+    component: () =>
+      import('@/views/dict/data')
   }
   }
+
   ]
   ]
 },
 },
 {
 {

+ 6 - 0
src/utils/errorCode.js

@@ -0,0 +1,6 @@
+export default {
+  '401': '认证失败,无法访问系统资源',
+  '403': '当前操作没有权限',
+  '404': '访问资源不存在',
+  'default': '系统未知错误,请反馈给管理员'
+}

+ 119 - 0
src/utils/request.js

@@ -0,0 +1,119 @@
+import axios from 'axios'
+import { Notification, MessageBox, Message } from 'element-ui'
+import store from '@/store'
+// import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
+import { tansParams } from '@/utils/ruoyi'
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+// 创建axios实例
+const service = axios.create({
+  // axios中请求配置有baseURL选项,表示请求URL公共部分
+  baseURL: process.env.VUE_APP_BASE_API,
+  // 超时
+  timeout: 10000
+})
+
+// request拦截器
+service.interceptors.request.use(config => {
+  // 是否需要设置 token
+  // const isToken = (config.headers || {}).isToken === false
+  // if (getToken() && !isToken) {
+  //   config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
+  // }
+  // get请求映射params参数
+  if (config.method === 'get' && config.params) {
+    let url = config.url + '?' + tansParams(config.params)
+    url = url.slice(0, -1)
+    config.params = {}
+    config.url = url
+  }
+  return config
+}, error => {
+  console.log(error)
+  Promise.reject(error)
+})
+
+// 响应拦截器
+service.interceptors.response.use(res => {
+  // 未设置状态码则默认成功状态
+  const code = res.data.code || 200
+  // 获取错误信息
+  const msg = errorCode[code] || res.data.msg || errorCode['default']
+  if (code === 401) {
+    MessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', {
+      confirmButtonText: '重新登录',
+      cancelButtonText: '取消',
+      type: 'warning'
+    }
+    ).then(() => {
+      store.dispatch('LogOut').then(() => {
+        location.href = '/index'
+      })
+    }).catch(() => { })
+    return Promise.reject()
+  } else if (code === 500) {
+    Message({
+      message: msg,
+      type: 'error'
+    })
+    return Promise.reject(new Error(msg))
+  } else if (code !== 200) {
+    Notification.error({
+      title: msg
+    })
+    return Promise.reject('error')
+  } else {
+    return res.data
+  }
+}
+  // error => {
+  //   console.log('err' + error)
+  //   let { message } = error
+  //   if (message == 'Network Error') {
+  //     message = '后端接口连接异常'
+  //   } else if (message.includes('timeout')) {
+  //     message = '系统接口请求超时'
+  //   } else if (message.includes('Request failed with status code')) {
+  //     message = '系统接口' + message.substr(message.length - 3) + '异常'
+  //   }
+  //   Message({
+  //     message: message,
+  //     type: 'error',
+  //     duration: 5 * 1000
+  //   })
+  //   return Promise.reject(error)
+  // }
+)
+
+// 通用下载方法
+export function download(url, params, filename) {
+  return service.post(url, params, {
+    transformRequest: [(params) => {
+      return tansParams(params)
+    }],
+    headers: {
+      'Content-Type': 'application/x-www-form-urlencoded'
+    },
+    responseType: 'blob'
+  }).then((data) => {
+    const content = data
+    const blob = new Blob([content])
+    if ('download' in document.createElement('a')) {
+      const elink = document.createElement('a')
+      elink.download = filename
+      elink.style.display = 'none'
+      elink.href = URL.createObjectURL(blob)
+      document.body.appendChild(elink)
+      elink.click()
+      URL.revokeObjectURL(elink.href)
+      document.body.removeChild(elink)
+    } else {
+      navigator.msSaveBlob(blob, filename)
+    }
+  }).catch((r) => {
+    console.error(r)
+  })
+}
+
+export default service

+ 199 - 0
src/utils/ruoyi.js

@@ -0,0 +1,199 @@
+/**
+ * 通用js方法封装处理
+ * Copyright (c) 2019 ruoyi
+ */
+
+const baseURL = process.env.VUE_APP_BASE_API
+
+// 日期格式化
+export function parseTime(time, pattern) {
+  if (arguments.length === 0 || !time) {
+    return null
+  }
+  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+      time = parseInt(time)
+    } else if (typeof time === 'string') {
+      time = time.replace(new RegExp(/-/gm), '/')
+    }
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value] }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+// 表单重置
+export function resetForm(refName) {
+  if (this.$refs[refName]) {
+    this.$refs[refName].resetFields()
+  }
+}
+
+// 添加日期范围
+export function addDateRange(params, dateRange, propName) {
+  var search = params
+  search.params = {}
+  if (dateRange !== null && dateRange !== '') {
+    if (typeof (propName) === 'undefined') {
+      search.params['beginTime'] = dateRange[0]
+      search.params['endTime'] = dateRange[1]
+    } else {
+      search.params['begin' + propName] = dateRange[0]
+      search.params['end' + propName] = dateRange[1]
+    }
+  }
+  return search
+}
+
+// 回显数据字典
+export function selectDictLabel(datas, value) {
+  var actions = []
+  Object.keys(datas).some((key) => {
+    if (datas[key].dictValue === ('' + value)) {
+      actions.push(datas[key].dictLabel)
+      return true
+    }
+  })
+  return actions.join('')
+}
+
+// 回显数据字典(字符串数组)
+export function selectDictLabels(datas, value, separator) {
+  var actions = []
+  var currentSeparator = undefined === separator ? ',' : separator
+  var temp = value.split(currentSeparator)
+  Object.keys(value.split(currentSeparator)).some((val) => {
+    Object.keys(datas).some((key) => {
+      if (datas[key].dictValue === ('' + temp[val])) {
+        actions.push(datas[key].dictLabel + currentSeparator)
+      }
+    })
+  })
+  return actions.join('').substring(0, actions.join('').length - 1)
+}
+
+// 通用下载方法
+export function download(fileName) {
+  window.location.href = baseURL + '/common/download?fileName=' + encodeURI(fileName) + '&delete=' + true
+}
+
+// 字符串格式化(%s )
+export function sprintf(str) {
+  var args = arguments; var flag = true; var i = 1
+  str = str.replace(/%s/g, function () {
+    var arg = args[i++]
+    if (typeof arg === 'undefined') {
+      flag = false
+      return ''
+    }
+    return arg
+  })
+  return flag ? str : ''
+}
+
+// 转换字符串,undefined,null等转化为""
+export function praseStrEmpty(str) {
+  if (!str || str === 'undefined' || str === 'null') {
+    return ''
+  }
+  return str
+}
+
+/**
+ * 构造树型结构数据
+ * @param {*} data 数据源
+ * @param {*} id id字段 默认 'id'
+ * @param {*} parentId 父节点字段 默认 'parentId'
+ * @param {*} children 孩子节点字段 默认 'children'
+ */
+export function handleTree(data, id, parentId, children) {
+  const config = {
+    id: id || 'id',
+    parentId: parentId || 'parentId',
+    childrenList: children || 'children'
+  }
+
+  var childrenListMap = {}
+  var nodeIds = {}
+  var tree = []
+
+  for (const d of data) {
+    const parentId = d[config.parentId]
+    if (childrenListMap[parentId] == null) {
+      childrenListMap[parentId] = []
+    }
+    nodeIds[d[config.id]] = d
+    childrenListMap[parentId].push(d)
+  }
+
+  for (const d of data) {
+    const parentId = d[config.parentId]
+    if (nodeIds[parentId] == null) {
+      tree.push(d)
+    }
+  }
+
+  for (const t of tree) {
+    adaptToChildrenList(t)
+  }
+
+  function adaptToChildrenList(o) {
+    if (childrenListMap[o[config.id]] !== null) {
+      o[config.childrenList] = childrenListMap[o[config.id]]
+    }
+    if (o[config.childrenList]) {
+      for (const c of o[config.childrenList]) {
+        adaptToChildrenList(c)
+      }
+    }
+  }
+  return tree
+}
+
+/**
+* 参数处理
+* @param {*} params  参数
+*/
+export function tansParams(params) {
+  let result = ''
+  for (const propName of Object.keys(params)) {
+    const value = params[propName]
+    var part = encodeURIComponent(propName) + '='
+    if (value !== null && typeof (value) !== 'undefined') {
+      if (typeof value === 'object') {
+        for (const key of Object.keys(value)) {
+          const params = propName + '[' + key + ']'
+          var subPart = encodeURIComponent(params) + '='
+          result += subPart + encodeURIComponent(value[key]) + '&'
+        }
+      } else {
+        result += part + encodeURIComponent(value) + '&'
+      }
+    }
+  }
+  return result
+}

+ 58 - 0
src/utils/scroll-to.js

@@ -0,0 +1,58 @@
+Math.easeInOutQuad = function(t, b, c, d) {
+  t /= d / 2
+  if (t < 1) {
+    return c / 2 * t * t + b
+  }
+  t--
+  return -c / 2 * (t * (t - 2) - 1) + b
+}
+
+// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
+var requestAnimFrame = (function() {
+  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
+})()
+
+/**
+ * Because it's so fucking difficult to detect the scrolling element, just move them all
+ * @param {number} amount
+ */
+function move(amount) {
+  document.documentElement.scrollTop = amount
+  document.body.parentNode.scrollTop = amount
+  document.body.scrollTop = amount
+}
+
+function position() {
+  return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
+}
+
+/**
+ * @param {number} to
+ * @param {number} duration
+ * @param {Function} callback
+ */
+export function scrollTo(to, duration, callback) {
+  const start = position()
+  const change = to - start
+  const increment = 20
+  let currentTime = 0
+  duration = (typeof (duration) === 'undefined') ? 500 : duration
+  var animateScroll = function() {
+    // increment the time
+    currentTime += increment
+    // find the value with the quadratic in-out easing function
+    var val = Math.easeInOutQuad(currentTime, start, change, duration)
+    // move the document.body
+    move(val)
+    // do the animation unless its over
+    if (currentTime < duration) {
+      requestAnimFrame(animateScroll)
+    } else {
+      if (callback && typeof (callback) === 'function') {
+        // the animation is done so lets callback
+        callback()
+      }
+    }
+  }
+  animateScroll()
+}

+ 117 - 0
src/views/basicSetting/label/basicSettingLabel/BasicSettingLabelMain.vue

@@ -0,0 +1,117 @@
+<template>
+  <div>
+    <Search ref="search" />
+    <el-row type="flex" justify="space-between" class="operate-box">
+      <el-button type="primary" icon="el-icon-plus" round @click="showAdd">新 增</el-button>
+    </el-row>
+    <div class="table-container">
+      <el-table v-loading="loading" stripe class="list-table" :data="data">
+        <c-data-empty slot="empty" />
+        <el-table-column label="操作" width="100">
+          <template slot-scope="{row}">
+            <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+            <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+          </template>
+        </el-table-column>
+        <el-table-column prop="bsLabelId" label="" width="100" align="center" />
+        <el-table-column prop="labelName" label="标签名称" width="100" align="center" />
+        <el-table-column prop="lableTypeId" label="类型id" width="100" align="center" />
+        <el-table-column prop="deleted" label="逻辑删除" width="100" align="center" />
+        <el-table-column prop="createBy" label="创建者" width="100" align="center" />
+        <el-table-column prop="createTime" label="创建时间" width="100" align="center" />
+        <el-table-column prop="updateBy" label="更新者" width="100" align="center" />
+        <el-table-column prop="updateTime" label="更新时间" width="100" align="center" />
+        <el-table-column prop="remark" label="备注" width="100" align="center" />
+      </el-table>
+    </div>
+    <c-pagination
+      :page-size.sync="pageInfo.pageSize"
+      :page-no.sync="pageInfo.pageNum"
+      :total="pageInfo.total"
+      :get-data-fun="loadData"
+    />
+    <OptionDialog ref="dialog" />
+  </div>
+</template>
+
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/label/basicSettingLabel'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+import { BasicSettingLabelEnt } from './object'
+export default {
+  name: 'BasicSettingLabel',
+  components: { Search, OptionDialog },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      data: [],
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.data = res.data.records
+        this.pageInfo.total = res.data.total
+        this.loading = false
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.id).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.show(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingLabelEnt())
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+</style>

+ 195 - 0
src/views/basicSetting/label/basicSettingLabel/OptionDialog.vue

@@ -0,0 +1,195 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="45%"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+
+      <el-form-item label="分类名称" prop="lableTypeName">
+        <el-input v-model="ent.lableTypeName" disabled />
+      </el-form-item>
+      <el-form-item v-if="!isEdit" label="" prop="labelName">
+        <div>
+          <el-row>
+            <el-col :span="19">
+              <p>输入标签名称多个标签请换行;不统计重复签名;失去光标自动去重</p>
+            </el-col>
+            <el-col :span="5">
+              <p style="color:#67C23A;font-weight: 600;">标签数:{{ addNum }}</p>
+            </el-col>
+          </el-row>
+        </div>
+        <el-input
+          v-model="ent.labelName"
+          type="textarea"
+          :autosize="{ minRows: 10, maxRows: 24}"
+          @input="textChange"
+          @blur="blurInput"
+        />
+      </el-form-item>
+      <el-form-item v-if="isEdit" label="标签名称" prop="labelName">
+        <el-input v-model="ent.labelName" />
+      </el-form-item>
+
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/label/basicSettingLabel'
+import { BasicSettingLabelEnt, formRules } from './object'
+
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      ent: new BasicSettingLabelEnt(),
+      addNum: 0,
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      cityList: []
+    }
+  },
+  methods: {
+    unique(arr) {
+      return Array.from(new Set(arr))
+    },
+    blurInput() {
+      var ct = this.ent.labelName.split('\n')
+      if (undefined !== ct) {
+        var res = this.unique(ct)
+        var cont = ''
+        res.forEach(item => {
+          if (cont !== '' && undefined !== cont) {
+            cont = cont + '\n' + item
+          } else {
+            cont = item
+          }
+        })
+        this.ent.labelName = cont
+      }
+    },
+
+    textChange() {
+      var ct = this.ent.labelName.split('\n')
+      var ind = 0
+      if (undefined !== ct) {
+        var res = this.unique(ct)
+        res.forEach(item => {
+          if (item !== '' && undefined !== item) {
+            ind = ind + 1
+          }
+        })
+        this.addNum = ind
+      }
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      req.labelName = this.ent.labelName.split('\n').toString()
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    showEd(isEdit = false, ent, row) {
+      if (isEdit) {
+        this.addNum = 0
+        this.ent = new BasicSettingLabelEnt()
+        this.ent.lableTypeId = ent.bsLabelTypeId
+        this.ent.lableTypeName = ent.labelTypeName
+        if (row.labelName !== undefined) {
+          this.ent.labelName = row.labelName
+        }
+      } else {
+        this.ent = ent
+      }
+      if (row.bsLabelId !== undefined) {
+        this.ent.bsLabelId = row.bsLabelId
+      }
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空')
+        }
+      })
+    },
+
+    show(isEdit = false, ent) {
+      if (!isEdit) {
+        this.addNum = 0
+        this.ent = new BasicSettingLabelEnt()
+        this.ent.lableTypeId = ent.bsLabelTypeId
+        this.ent.lableTypeName = ent.labelTypeName
+      } else {
+        this.ent = ent
+      }
+
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空')
+        }
+      })
+    }
+  }
+}
+</script>

+ 84 - 0
src/views/basicSetting/label/basicSettingLabel/Search.vue

@@ -0,0 +1,84 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="12">
+      <el-col :span="6">
+        <el-form-item prop="bsLabelId">
+          <el-input v-model="searchForm.bsLabelId" placeholder="" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="labelName">
+          <el-input v-model="searchForm.labelName" placeholder="标签名称" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="lableTypeId">
+          <el-input v-model="searchForm.lableTypeId" placeholder="类型id" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="deleted">
+          <el-input v-model="searchForm.deleted" placeholder="逻辑删除" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="createBy">
+          <el-input v-model="searchForm.createBy" placeholder="创建者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="createTime">
+          <el-input v-model="searchForm.createTime" placeholder="创建时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateBy">
+          <el-input v-model="searchForm.updateBy" placeholder="更新者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateTime">
+          <el-input v-model="searchForm.updateTime" placeholder="更新时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="remark">
+          <el-input v-model="searchForm.remark" placeholder="备注" />
+        </el-form-item>
+      </el-col>
+    </el-row>
+    <el-row>
+      <el-col :span="6">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row>
+  </el-form>
+</template>
+<script>
+import { searchForm } from './object'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      searchForm: searchForm
+    }
+  },
+  methods: {
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/label/basicSettingLabel/index.js

@@ -0,0 +1,3 @@
+import BasicSettingLabel from './BasicSettingLabelMain.vue'
+
+export default BasicSettingLabel

+ 30 - 0
src/views/basicSetting/label/basicSettingLabel/object.js

@@ -0,0 +1,30 @@
+export const searchForm = {
+  bsLabelId: null,
+  labelName: null,
+  lableTypeId: null,
+  deleted: null,
+  createBy: null,
+  createTime: null,
+  updateBy: null,
+  updateTime: null,
+  remark: null
+}
+
+export class BasicSettingLabelEnt {
+  bsLabelId
+  labelName
+  lableTypeId
+  lableTypeName
+  deleted
+  createBy
+  createTime
+  updateBy
+  updateTime
+  remark
+}
+
+export const formRules = {
+
+  labelName: [{ required: true, message: '请填写标签名称', trigger: 'change' }]
+
+}

+ 280 - 0
src/views/basicSetting/label/basicSettingLabelType/BasicSettingLabelTypeMain.vue

@@ -0,0 +1,280 @@
+<template>
+  <div>
+    <Search ref="search" />
+
+    <el-row>
+
+      <el-col :span="6" class="elStyle">
+        <el-row
+          type="flex"
+          justify="space-between"
+          class="operate-box"
+          style="display: flex;justify-content: center;"
+        >
+          <el-button type="primary" icon="el-icon-plus" style="    width: 100%;" @click="showAdd">新增标签分类</el-button>
+        </el-row>
+        <div class="table-container">
+          <el-table v-loading="loading" stripe class="list-table" :data="data">
+            <c-data-empty slot="empty" />
+            <el-table-column prop="labelTypeName" label="分类名称" align="center" :show-overflow-tooltip="true" />
+            <el-table-column prop="relationProjectName" label="所属项目" align="center" :show-overflow-tooltip="true" />
+            <el-table-column prop="num" label="标签数量" align="center">
+              <template slot-scope="scope">
+                <el-button :style="scope.row.color==='NO'? tableNo:tableNum" type="text" @click="buttonNum(scope.row.bsLabelTypeId)"><u :style="scope.row.color!=='NO'? 'color:#fff':''">{{ scope.row.num }}</u></el-button>
+              </template>
+            </el-table-column>
+            <el-table-column label="操作" fixed="right" :show-overflow-tooltip="true">
+              <template slot-scope="{row}">
+                <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+                <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <c-pagination
+          :page-size.sync="pageInfo.pageSize"
+          :page-no.sync="pageInfo.pageNum"
+          :total="pageInfo.total"
+          :get-data-fun="loadData"
+        />
+        <OptionDialog ref="dialog" />
+
+      </el-col>
+
+      <el-col :span="17" class="elStyle ml-10">
+        <el-row type="flex" justify="space-between" class="operate-box">
+          <el-col :span="22" style="">
+            <el-alert :title="'分类名称:'+labelTypeObj.labelTypeName" type="info" center :closable="false" />
+          </el-col>
+          <el-col :span="2">
+            <el-button type="primary" class="ml-5" icon="el-icon-plus" round @click="showAddLabel">新 增</el-button>
+          </el-col>
+        </el-row>
+        <div class="table-container">
+          <el-table v-loading="loading" stripe class="list-table" :data="dataLabel">
+            <c-data-empty slot="empty" />
+            <el-table-column type="index" label="序号" width="150" align="center" />
+            <el-table-column prop="labelName" label="标签名称" width="450" align="center" :show-overflow-tooltip="true" />
+            <el-table-column prop="num" label="已关联专辑" align="center" :show-overflow-tooltip="true" />
+            <!-- <el-table-column prop="createBy" label="创建者" align="center" />
+            <el-table-column prop="createTime" label="创建时间" align="center" />
+            <el-table-column prop="updateBy" label="更新者" align="center" />
+            <el-table-column prop="updateTime" label="更新时间" align="center" /> -->
+
+            <el-table-column label="操作">
+              <template slot-scope="{row}">
+                <el-button type="text" size="small" @click="showEd(row)">编辑</el-button>
+                <el-button type="text" size="small" @click="deleteRowLabel(row)">删除</el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </div>
+        <c-pagination
+          :page-size.sync="pageInfoLable.pageSize"
+          :page-no.sync="pageInfoLable.pageNum"
+          :total="pageInfoLable.total"
+          :get-data-fun="labelPage"
+        />
+        <OptionDialogLabel ref="dialogLabel" />
+
+      </el-col>
+    </el-row>
+
+  </div>
+</template>
+
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import { DeleteLabel } from '@/network/api/basicSetting/label/basicSettingLabel'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/label/basicSettingLabelType'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+import OptionDialogLabel from '../basicSettingLabel/OptionDialog'
+import { BasicSettingLabelTypeEnt } from './object'
+
+export default {
+  name: 'BasicSettingLabelType',
+  components: { Search, OptionDialog, OptionDialogLabel },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit
+    }
+  },
+  data() {
+    return {
+      cuntId: '',
+
+      tableNo: {
+        width: '100%',
+        height: '100%'
+      },
+      tableNum: {
+        width: '100%',
+        height: '100%',
+        backgroundColor: '#409EFF'
+      },
+      labelTypeObj: {},
+      labelObj: {},
+      dataLabel: [],
+      allDataLabel: [],
+      pageInfoLable: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      },
+
+      radioVal: undefined,
+      loading: false,
+      data: [],
+      height: '500px',
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    labelPage() {
+      var pageNum = this.pageInfoLable.pageNum
+      var pageSize = this.pageInfoLable.pageSize
+      if (undefined === this.allDataLabel) {
+        this.dataLabel = []
+        this.pageInfoLable.total = 0
+      } else {
+        this.dataLabel = this.allDataLabel.slice((pageNum - 1) * pageSize, this.allDataLabel.length > pageNum * pageSize ? pageNum * pageSize : this.allDataLabel.length)
+        this.pageInfoLable.total = this.allDataLabel.length
+      }
+    },
+    buttonNum(bsLabelTypeId) {
+      this.cuntId = bsLabelTypeId
+      this.data.forEach(item => {
+        if (item.bsLabelTypeId === bsLabelTypeId) {
+          item.color = 'YES'
+          this.labelTypeObj = item
+        } else {
+          item.color = 'NO'
+        }
+      })
+      if (undefined !== this.labelObj) {
+        debugger
+        this.allDataLabel = this.labelObj[bsLabelTypeId]
+        if (undefined === this.allDataLabel) {
+          this.dataLabel = []
+          this.pageInfoLable.total = 0
+        } else {
+          this.dataLabel = this.allDataLabel.slice(0, this.allDataLabel.length > 10 ? 10 : this.allDataLabel.length)
+          this.pageInfoLable.total = this.allDataLabel.length
+        }
+      }
+    },
+
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.data = res.data.LabelType
+        if (this.cuntId === '' && undefined !== this.data && this.data.length > 0) {
+          this.data[0].color = 'red'
+          this.labelTypeObj = this.data[0]
+        } else {
+          if (undefined !== this.data && this.data.length > 0) {
+            this.data.forEach(item => {
+              if (item.bsLabelTypeId === this.cuntId) {
+                this.labelTypeObj = item
+                this.labelTypeObj.color = 'red'
+              }
+            })
+          }
+        }
+
+        this.labelObj = res.data.Label
+        if (undefined !== this.labelObj) {
+          this.allDataLabel = this.labelObj[this.labelTypeObj.bsLabelTypeId]
+          if (undefined !== this.allDataLabel) {
+            this.dataLabel = this.allDataLabel.slice(0, this.allDataLabel.length > 10 ? 10 : this.allDataLabel.length)
+            this.pageInfoLable.total = this.allDataLabel.length
+          }
+        }
+
+        this.pageInfo.total = res.data.total
+        this.loading = false
+      })
+    },
+    deleteRowLabel(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        DeleteLabel(row.bsLabelId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.bsLabelTypeId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.show(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingLabelTypeEnt())
+    },
+    showAddLabel() {
+      this.$refs.dialogLabel.show(false, this.labelTypeObj)
+    },
+
+    showEd(row) {
+      this.$refs.dialogLabel.showEd(true, this.labelTypeObj, row)
+    }
+  }
+}
+</script>
+
+<style scoped>
+
+.elStyle{
+   border: 1px solid #EDECF2;height:740px
+}
+
+</style>

+ 171 - 0
src/views/basicSetting/label/basicSettingLabelType/OptionDialog.vue

@@ -0,0 +1,171 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="45%"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+
+      <el-form-item label="标签分类名称" prop="labelTypeName">
+        <el-input v-model="ent.labelTypeName" maxlength="15" placeholder="最大输入长度15 超出截断" />
+      </el-form-item>
+      <el-form-item label="关联项目" prop="relationProjectId">
+        <el-select v-model="ent.relationProjectId" multiple filterable placeholder="请选择" @change="selectChange">
+          <el-option
+            v-for="item in options"
+            :key="item.bsProjectId"
+            :label="item.projectName"
+            :value="item.bsProjectId"
+          />
+        </el-select>
+        <!-- <el-input v-model="ent.relationProjectId" /> -->
+      </el-form-item>
+
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/label/basicSettingLabelType'
+import { BasicSettingLabelTypeEnt, formRules } from './object'
+import {
+  getProjectForSource
+} from '@/network/api/basicSetting/project/basicSettingProject'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      ent: new BasicSettingLabelTypeEnt(),
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      options: [],
+      cityList: []
+    }
+  },
+  mounted() {
+    this.getProject()
+  },
+  methods: {
+    selectChange(val) {
+      debugger
+      if (val !== undefined && val.length > 0) {
+        var content = ''
+        val.forEach(item => {
+          var arr2 = this.options.filter(w => w.bsProjectId === item)
+          if (arr2.length > 0) {
+            if (content === '') {
+              content = arr2[0].projectName
+            } else {
+              content = content + ',' + arr2[0].projectName
+            }
+          }
+        })
+        this.ent.relationProjectName = content
+      }
+    },
+    getProject() {
+      getProjectForSource().then(x => {
+        if (x.code === 200) {
+          this.options = x.data
+        }
+      })
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      req.relationProjectId = req.relationProjectId.toString()
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      req.relationProjectId = req.relationProjectId.toString()
+
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    show(isEdit = false, ent) {
+      if (isEdit) {
+        this.ent = new BasicSettingLabelTypeEnt()
+        this.ent.bsLabelTypeId = ent.bsLabelTypeId
+        this.ent.labelTypeName = ent.labelTypeName
+        this.ent.relationProjectName = ent.relationProjectName
+        if (ent.relationProjectId !== undefined && ent.relationProjectId !== null) {
+          const arrays = ent.relationProjectId.split(',')
+          if (arrays !== undefined) {
+            this.ent.relationProjectId = []
+            arrays.forEach(item => {
+              this.ent.relationProjectId.push(Number(item))
+            })
+          }
+        }
+      } else {
+        this.ent = ent
+        this.ent.relationProjectId = []
+      }
+
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空')
+        }
+      })
+    }
+  }
+}
+</script>

+ 68 - 0
src/views/basicSetting/label/basicSettingLabelType/Search.vue

@@ -0,0 +1,68 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="12">
+
+      <el-col :span="3">
+        <el-form-item prop="labelTypeName">
+          <el-input v-model="searchForm.labelTypeName" placeholder="标签分类名称" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="relationProjectId">
+          <el-select v-model="searchForm.relationProjectId" filterable placeholder="请选择">
+            <el-option
+              v-for="item in options"
+              :key="item.bsProjectId"
+              :label="item.projectName"
+              :value="item.bsProjectId"
+            />
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row>
+
+  </el-form>
+</template>
+<script>
+import { searchForm } from './object'
+import { getProjectForSource } from '@/network/api/basicSetting/project/basicSettingProject'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      options: [],
+      searchForm: searchForm
+    }
+  },
+  mounted() {
+    this.getProject()
+  },
+  methods: {
+    getProject() {
+      getProjectForSource().then(x => {
+        if (x.code === 200) {
+          this.options = x.data
+        }
+      })
+    },
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/label/basicSettingLabelType/index.js

@@ -0,0 +1,3 @@
+import BasicSettingLabelType from './BasicSettingLabelTypeMain.vue'
+
+export default BasicSettingLabelType

+ 32 - 0
src/views/basicSetting/label/basicSettingLabelType/object.js

@@ -0,0 +1,32 @@
+export const searchForm = {
+  bsLabelTypeId: null,
+  labelTypeName: null,
+  relationProjectId: null,
+  relationProjectName: null,
+  deleted: null,
+  createBy: null,
+  createTime: null,
+  updateBy: null,
+  updateTime: null,
+  remark: null
+}
+
+export class BasicSettingLabelTypeEnt {
+  bsLabelTypeId
+  labelTypeName
+  relationProjectId
+  relationProjectName
+  deleted
+  createBy
+  createTime
+  updateBy
+  updateTime
+  remark
+}
+
+export const formRules = {
+
+  labelTypeName: [{ required: true, message: '请填写标签分类名称', trigger: 'change' }],
+  relationProjectId: [{ required: true, message: '请填写关联项目id', trigger: 'change' }]
+
+}

+ 261 - 0
src/views/basicSetting/product/item/BasicSettingProductMain.vue

@@ -0,0 +1,261 @@
+<template>
+  <div>
+    <Search ref="search" />
+    <el-row type="flex" justify="space-between" class="operate-box">
+      <el-col v-if="visibelOpt" :span="10">
+        <el-button type="primary" round @click="showOpt">批量操作 <i class="el-icon-right" /></el-button>
+      </el-col>
+      <el-col v-if="!visibelOpt" :span="10">
+        <el-button type="primary" icon="el-icon-edit" :disabled="disabledTF" round @click="showOpts('type')">修改品类</el-button>
+        <el-button type="primary" icon="el-icon-edit" :disabled="sourceDisabled" round @click="showOpts('source')">修改来源</el-button>
+        <el-button type="primary" icon="el-icon-edit" :disabled="disabledTF" round @click="showOpts('project')">修改项目</el-button>
+        <el-button type="success" icon="el-icon-check" :disabled="disabledTF" round @click="showOpts('start')">批量启用</el-button>
+        <el-button type="danger" icon="el-icon-close" :disabled="disabledTF" round @click="showOpts('end')">批量不启用</el-button>
+        <el-button type="info" icon="el-icon-back" round @click="showOpt">隐藏</el-button>
+      </el-col>
+      <el-col :span="2">
+        <el-button type="primary" icon="el-icon-plus" round @click="showAdd">新 增</el-button>
+      </el-col>
+
+    </el-row>
+    <div class="table-container">
+      <el-table
+        v-loading="loading"
+        stripe
+        class="list-table"
+        :data="data"
+        @selection-change="handleSelectionChange"
+      >
+        >
+        <c-data-empty slot="empty" />
+        <el-table-column type="selection" />
+        <el-table-column type="index" width="50" label="序号" align="center" />
+        <el-table-column prop="productName" label="产品名称" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="productTypeName" label="产品品类名称" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="productSourceName" label="产品来源名称" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="relationProjectName" label="关联项目名称" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="isUseing" label="是否启用" align="center">
+          <template slot-scope="scope">
+            <div v-if=" scope.row.isUseing==='ISUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="启用" type="success" center show-icon :closable="false" />
+            </div>
+            <div v-if=" scope.row.isUseing==='ISNOTUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="不启用" type="error" center show-icon :closable="false" />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="备注" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="createBy" label="创建者" align="center" />
+        <el-table-column prop="createTime" label="创建时间" width="150" align="center" />
+        <el-table-column prop="updateBy" label="更新者" align="center" />
+        <el-table-column prop="updateTime" label="更新时间" width="150" align="center" />
+        <el-table-column label="操作" width="100">
+          <template slot-scope="{row}">
+            <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+            <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <c-pagination
+      :page-size.sync="pageInfo.pageSize"
+      :page-no.sync="pageInfo.pageNum"
+      :total="pageInfo.total"
+      :get-data-fun="loadData"
+    />
+    <OptionDialog ref="dialog" />
+    <ProjectOptionDialog ref="proj" />
+    <ProductTypeDialog ref="typelog" />
+    <ProductSourceDialog ref="sourcelog" />
+    <OptOptionDialog ref="optlog" />
+  </div>
+</template>
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/product/basicSettingProduct'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+import OptOptionDialog from './OptOptionDialog'
+import ProjectOptionDialog from '../../project/OptionDialog'
+import { BasicSettingProjectEnt } from '../../project/object'
+import ProductTypeDialog from '../type/OptionDialog'
+import { BasicSettingProductTypeEnt } from '../type/object'
+import ProductSourceDialog from '../source/OptionDialog'
+import { BasicSettingProductSourceEnt } from '../source/object'
+import { BasicSettingProductEnt } from './object'
+import {
+  updateBatch
+} from '@/network/api/basicSetting/product/basicSettingProduct'
+export default {
+  name: 'BasicSettingProduct',
+  components: { Search, OptionDialog, ProjectOptionDialog, ProductTypeDialog, ProductSourceDialog, OptOptionDialog },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit,
+      showAddProject: this.showAddProject,
+      showAddType: this.showAddType,
+      showAddSource: this.showAddSource
+    }
+  },
+  data() {
+    return {
+      disabledTF: true,
+      sourceDisabled: true,
+      visibelOpt: true,
+      loading: false,
+      data: [],
+      multipleSelection: [],
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+      if (this.multipleSelection === undefined || this.multipleSelection === null || this.multipleSelection.length === 0) {
+        this.disabledTF = true
+      } else {
+        this.disabledTF = false
+      }
+      let status = '0'
+      let projectId = ''
+      this.multipleSelection.forEach(w => {
+        if (projectId === '') {
+          projectId = w.relationProjectId
+        } else {
+          if (projectId !== w.relationProjectId && status === '0') {
+            status = '1'
+          }
+        }
+      })
+      if (status === '0' && !this.disabledTF) {
+        this.sourceDisabled = false
+      } else {
+        this.sourceDisabled = true
+      }
+    },
+    showOpt() {
+      this.visibelOpt = !this.visibelOpt
+    },
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.data = res.data.records
+        this.pageInfo.total = res.data.total
+        this.loading = false
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.bsProductId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.show(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingProductEnt())
+    },
+    showAddProject() {
+      this.$refs.proj.show(false, new BasicSettingProjectEnt())
+    },
+    showAddType() {
+      this.$refs.typelog.show(false, new BasicSettingProductTypeEnt())
+    },
+    showAddSource() {
+      this.$refs.sourcelog.show(false, new BasicSettingProductSourceEnt())
+    },
+    showOpts(type) {
+      let status = '0'
+
+      let projectId = ''
+      const array = []
+      this.multipleSelection.forEach(w => {
+        array.push(w.bsProductId)
+        if (projectId === '') {
+          projectId = w.relationProjectId
+        } else {
+          if (projectId !== w.relationProjectId && status === '0') {
+            status = '1'
+          }
+        }
+      })
+      if (array.length === 0) {
+        this.$message({
+          type: 'error',
+          message: '请选择'
+        })
+        return
+      }
+      if (type === 'source') {
+        if (array.length === 1 || (array.length > 1 && status === '0')) {
+          this.$refs.optlog.show(type, array, projectId)
+        } else {
+          this.$message({
+            type: 'error',
+            message: '请选择关联项目相同的数据'
+          })
+        }
+      }
+      if (type === 'type' || type === 'project') {
+        this.$refs.optlog.show(type, array, undefined)
+      }
+
+      if (type === 'start' || type === 'end') {
+        updateBatch({ 'ids': array.toString(), 'type': type }).then(res => {
+          this.$message({
+            message: '修改成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.el-alert--success.is-light {
+    background-color: #f0f9eb;
+    color: #67C23A;
+    padding: 0;
+}
+.el-alert--error.is-light {
+    background-color: #fef0f0;
+    color: #F56C6C;
+    padding: 0;
+}
+</style>

+ 235 - 0
src/views/basicSetting/product/item/OptOptionDialog.vue

@@ -0,0 +1,235 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="580px"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+
+      <el-form-item v-if="type==='type'" label="产品品类" prop="productTypeId">
+        <el-select
+          v-model="ent.productTypeId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="productType"
+        >
+          <el-option
+            v-for="item in typeList"
+            :key="item.bsProductTypeId"
+            :label="item.typeName"
+            :value="item.bsProductTypeId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="typeAdd"><u>新增品类</u></el-button>
+        <!-- <el-input v-model="ent.productTypeId" /> -->
+      </el-form-item>
+
+      <el-form-item v-if="type==='project'" label="关联项目" prop="relationProjectId">
+        <el-select
+          v-model="ent.relationProjectId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="projectChange"
+        >
+          <el-option
+            v-for="item in projectList"
+            :key="item.bsProjectId"
+            :label="item.projectName"
+            :value="item.bsProjectId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="projectAdd"><u>新增项目</u></el-button>
+      </el-form-item>
+
+      <el-form-item v-if="type==='source' || type==='project'" label="产品来源" prop="productSourceId">
+        <el-select
+          v-model="ent.productSourceId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="sourceChange"
+        >
+          <el-option
+            v-for="item in sourceList"
+            :key="item.bsProductSourceId"
+            :label="item.source"
+            :value="item.bsProductSourceId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="sourceAdd"><u>新增来源</u></el-button>
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  updateBatch
+} from '@/network/api/basicSetting/product/basicSettingProduct'
+import { BasicSettingProductEnt, formRules, isUseingList } from './object'
+import { getProjectForProduct } from '@/network/api/basicSetting/project/basicSettingProject'
+import { getAllIsUseing } from '@/network/api/basicSetting/product/basicSettingProductType'
+
+export default {
+  inject: ['loadData', 'showAddProject', 'showAddType', 'showAddSource'],
+  data() {
+    return {
+      ent: new BasicSettingProductEnt(),
+      rules: formRules,
+      type: '',
+      isEdit: false,
+      visible: false,
+      isUseingList: isUseingList,
+      ids: [],
+      cityList: [],
+      typeList: [],
+      projectList: [],
+      sourceList: [],
+      objSoucer: {}
+    }
+  },
+
+  methods: {
+    projectAdd() {
+      this.close()
+      this.showAddProject()
+    },
+    typeAdd() {
+      this.close()
+      this.showAddType()
+    },
+    sourceAdd() {
+      this.close()
+      this.showAddSource()
+    },
+    productType(val) {
+      this.typeList.forEach(item => {
+        if (item.bsProductTypeId === val) {
+          this.ent.productTypeName = item.typeName
+        }
+      })
+    },
+    projectChange(val) {
+      this.sourceList = []
+      this.ent.productSourceId = undefined
+      this.ent.productSourceName = undefined
+      if (this.objSoucer[val] !== undefined) {
+        this.sourceList = this.objSoucer[val]
+      }
+      this.projectList.forEach(item => {
+        if (item.bsProjectId === val) {
+          this.ent.relationProjectName = item.projectName
+        }
+      })
+    },
+    sourceChange(val) {
+      this.sourceList.forEach(item => {
+        if (item.bsProductSourceId === val) {
+          this.ent.productSourceName = item.source
+        }
+      })
+    },
+
+    getType() {
+      getAllIsUseing().then(res => {
+        if (res.code === 200) {
+          this.typeList = res.data
+          console.log(this.typeList)
+        }
+      })
+    },
+    getProject() {
+      getProjectForProduct().then(res => {
+        if (res.code === 200) {
+          const data = res.data
+          if (undefined !== data.PROJECT) {
+            this.projectList = data.PROJECT
+            console.log(this.projectList)
+          }
+          if (undefined !== data.SOURCE) {
+            this.objSoucer = data.SOURCE
+            console.log(this.objSoucer)
+          }
+        }
+      })
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.updateRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      Add(req).then(res => {
+        this.$message({
+          message: '保存成功',
+          type: 'success'
+        })
+        this.loadData()
+        this.close()
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      req.ids = this.ids.toString()
+      req.type = this.type
+      updateBatch(req).then(res => {
+        this.$message({
+          message: '修改成功',
+          type: 'success'
+        })
+        this.loadData()
+        this.close()
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    shows(isEdit = false, ent) {
+      if (!isEdit) {
+        ent.isUseing = 'ISUSEING'
+      }
+      this.ent = ent
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空')
+        }
+      })
+    },
+
+    show(type, ids, projectid) {
+      this.visible = true
+      if (undefined !== projectid) {
+        this.projectChange(projectid)
+      }
+      if (type === 'type') {
+        this.getType()
+      } else {
+        this.getProject()
+      }
+      this.ids = ids
+      this.type = type
+    }
+  }
+}
+</script>

+ 310 - 0
src/views/basicSetting/product/item/OptionDialog.vue

@@ -0,0 +1,310 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="45%"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+
+      <el-form-item label="产品名称" prop="productName">
+        <el-input v-model="ent.productName" maxlength="30" placeholder="最大输入长度30 超出截断" />
+      </el-form-item>
+      <el-form-item label="产品品类" prop="productTypeId">
+        <el-select
+          v-model="ent.productTypeId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="productType"
+        >
+          <el-option
+            v-for="item in typeList"
+            :key="item.bsProductTypeId"
+            :label="item.typeName"
+            :value="item.bsProductTypeId"
+          />
+        </el-select>
+
+        <el-button class="ml-10" type="text" @click="typeAdd"><u>新增品类</u></el-button>
+        <el-tooltip class="item" effect="dark" content="刷新产品品类选择内容" placement="top-start">
+          <el-button class="ml-10" type="text" icon="el-icon-refresh" @click="refreshRest" />
+        </el-tooltip>
+        <!-- <el-input v-model="ent.productTypeId" /> -->
+      </el-form-item>
+      <el-form-item label="关联项目" prop="relationProjectId">
+        <el-select
+          v-model="ent.relationProjectId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="projectChange"
+        >
+          <el-option
+            v-for="item in projectList"
+            :key="item.bsProjectId"
+            :label="item.projectName"
+            :value="item.bsProjectId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="projectAdd"><u>新增项目</u></el-button>
+        <el-tooltip class="item" effect="dark" content="刷新关联项目选择内容" placement="top-start">
+          <el-button class="ml-10" type="text" icon="el-icon-refresh" @click="refreshRest" />
+        </el-tooltip>
+      </el-form-item>
+      <el-form-item label="产品来源" prop="productSourceId">
+        <el-select
+          v-model="ent.productSourceId"
+          filterable
+          default-first-option
+          placeholder="请选择"
+          @change="sourceChange"
+        >
+          <el-option
+            v-for="item in sourceList"
+            :key="item.bsProductSourceId"
+            :label="item.source"
+            :value="item.bsProductSourceId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="sourceAdd"><u>新增来源</u></el-button>
+        <el-tooltip class="item" effect="dark" content="刷新产品来源选择内容" placement="top-start">
+          <el-button class="ml-10" type="text" icon="el-icon-refresh" @click="refreshRest" />
+        </el-tooltip>
+      </el-form-item>
+      <el-form-item label="是否启用" prop="isUseing">
+        <el-select
+          v-model="ent.isUseing"
+
+          filterable
+          default-first-option
+          placeholder="请选择"
+        >
+          <el-option
+            v-for="item in isUseingList"
+            :key="item.value"
+            :label="item.label"
+            :value="item.value"
+          />
+        </el-select>
+
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="ent.remark" type="textarea" maxlength="100" min="0" placeholder="最大输入长度100 超出截断" />
+      </el-form-item>
+      <!-- <el-form-item label="关联项目名称" prop="relationProjectName">
+        <el-input v-model="ent.relationProjectName" />
+      </el-form-item> -->
+      <!-- <el-form-item label="产品类型名称" prop="productTypeName">
+        <el-input v-model="ent.productTypeName" />
+      </el-form-item> -->
+
+      <!-- <el-form-item label="产品来源名称" prop="productSourceName">
+        <el-input v-model="ent.productSourceName" />
+      </el-form-item> -->
+      <!-- <el-form-item label="产品组id" prop="productGroupId">
+        <el-input v-model="ent.productGroupId" />
+      </el-form-item>
+      <el-form-item label="产品组名称" prop="productGroupName">
+        <el-input v-model="ent.productGroupName" />
+      </el-form-item> -->
+
+      <!-- <el-form-item label="逻辑删除" prop="deleted">
+        <el-input v-model="ent.deleted" />
+      </el-form-item>
+      <el-form-item label="创建者" prop="createBy">
+        <el-input v-model="ent.createBy" />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-input v-model="ent.createTime" />
+      </el-form-item>
+      <el-form-item label="更新者" prop="updateBy">
+        <el-input v-model="ent.updateBy" />
+      </el-form-item>
+      <el-form-item label="更新时间" prop="updateTime">
+        <el-input v-model="ent.updateTime" />
+      </el-form-item> -->
+
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/product/basicSettingProduct'
+import { BasicSettingProductEnt, formRules, isUseingList } from './object'
+import { getProjectForProduct } from '@/network/api/basicSetting/project/basicSettingProject'
+import { getAllIsUseing } from '@/network/api/basicSetting/product/basicSettingProductType'
+
+export default {
+  inject: ['loadData', 'showAddProject', 'showAddType', 'showAddSource'],
+  data() {
+    return {
+      ent: new BasicSettingProductEnt(),
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      isUseingList: isUseingList,
+      cityList: [],
+      typeList: [],
+      projectList: [],
+      sourceList: [],
+      objSoucer: {}
+    }
+  },
+  mounted() {
+    this.getType()
+    this.getProject()
+  },
+
+  methods: {
+    refreshRest() {
+      this.getType()
+      this.getProject()
+    },
+    activateds() {
+      this.$message({
+        message: '激活',
+        type: 'success'
+      })
+    },
+    projectAdd() {
+      // this.close()
+      this.showAddProject()
+    },
+    typeAdd() {
+      // this.close()
+      this.showAddType()
+    },
+    sourceAdd() {
+      // this.close()
+      this.showAddSource()
+    },
+    productType(val) {
+      this.typeList.forEach(item => {
+        if (item.bsProductTypeId === val) {
+          this.ent.productTypeName = item.typeName
+        }
+      })
+    },
+    projectChange(val) {
+      this.sourceList = []
+      this.ent.productSourceId = undefined
+      this.ent.productSourceName = undefined
+      if (this.objSoucer[val] !== undefined) {
+        this.sourceList = this.objSoucer[val]
+      }
+      this.projectList.forEach(item => {
+        if (item.bsProjectId === val) {
+          this.ent.relationProjectName = item.projectName
+        }
+      })
+    },
+    sourceChange(val) {
+      this.sourceList.forEach(item => {
+        if (item.bsProductSourceId === val) {
+          this.ent.productSourceName = item.source
+        }
+      })
+    },
+
+    getType() {
+      getAllIsUseing().then(res => {
+        if (res.code === 200) {
+          this.typeList = res.data
+        }
+      })
+    },
+    getProject() {
+      getProjectForProduct().then(res => {
+        if (res.code === 200) {
+          const data = res.data
+          if (undefined !== data.PROJECT) {
+            this.projectList = data.PROJECT
+          }
+          if (undefined !== data.SOURCE) {
+            this.objSoucer = data.SOURCE
+          }
+        }
+      })
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    show(isEdit = false, ent) {
+      this.getType()
+      this.getProject()
+      if (!isEdit) {
+        ent.isUseing = 'ISUSEING'
+      }
+      this.ent = ent
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          if (this.objSoucer[this.ent.relationProjectId] !== undefined) {
+            this.sourceList = this.objSoucer[this.ent.relationProjectId]
+          }
+        }
+      })
+    }
+  }
+}
+</script>

+ 207 - 0
src/views/basicSetting/product/item/Search.vue

@@ -0,0 +1,207 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="12">
+
+      <el-col :span="3">
+        <el-form-item prop="productName">
+          <el-input v-model="searchForm.productName" placeholder="产品名称" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="3">
+        <el-form-item prop="productTypeId">
+          <el-select
+            v-model="searchForm.productTypeId"
+            filterable
+            default-first-option
+            placeholder="产品品类"
+          >
+            <el-option
+              v-for="item in typeList"
+              :key="item.bsProductTypeId"
+              :label="item.typeName"
+              :value="item.bsProductTypeId"
+            />
+          </el-select>
+          <!-- <el-input v-model="searchForm.productTypeId" placeholder="产品品类" /> -->
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="relationProjectId">
+          <el-select
+            v-model="searchForm.relationProjectId"
+            filterable
+            default-first-option
+            placeholder="关联项目"
+            @change="projectChange"
+          >
+            <el-option
+              v-for="item in projectList"
+              :key="item.bsProjectId"
+              :label="item.projectName"
+              :value="item.bsProjectId"
+            />
+          </el-select>
+          <!-- <el-input v-model="searchForm.relationProjectName" placeholder="关联项目名称" /> -->
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="productSourceId">
+          <el-select
+            v-model="searchForm.productSourceId"
+            filterable
+            default-first-option
+            placeholder="产品来源"
+          >
+            <el-option
+              v-for="item in sourceList"
+              :key="item.bsProductSourceId"
+              :label="item.source"
+              :value="item.bsProductSourceId"
+            />
+          </el-select>
+          <!-- <el-input v-model="searchForm.productSourceId" placeholder="产品来源" /> -->
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="3">
+        <el-form-item prop="isUseing">
+          <el-select
+            v-model="searchForm.isUseing"
+
+            filterable
+            default-first-option
+            placeholder="是否启用"
+          >
+            <el-option
+              v-for="item in isUseingList"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+          <!-- <el-input v-model="searchForm.isUseing" placeholder="是否启用" /> -->
+        </el-form-item>
+      </el-col>
+      <!-- </el-col>
+      <el-col :span="6">
+        <el-form-item prop="deleted">
+          <el-input v-model="searchForm.deleted" placeholder="逻辑删除" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="createBy">
+          <el-input v-model="searchForm.createBy" placeholder="创建者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="createTime">
+          <el-input v-model="searchForm.createTime" placeholder="创建时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateBy">
+          <el-input v-model="searchForm.updateBy" placeholder="更新者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateTime">
+          <el-input v-model="searchForm.updateTime" placeholder="更新时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="remark">
+          <el-input v-model="searchForm.remark" placeholder="备注" />
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="3">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row>
+
+  </el-form>
+</template>
+<script>
+import { searchForm, isUseingList } from './object'
+import { getIsUseingData } from '@/network/api/basicSetting/product/basicSettingProductSource'
+import { getAllIsUseing } from '@/network/api/basicSetting/product/basicSettingProductType'
+import { getProjectForProduct } from '@/network/api/basicSetting/project/basicSettingProject'
+
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      searchForm: searchForm,
+      isUseingList: isUseingList,
+      sourceListBackups: [],
+      sourceList: [],
+      projectList: [],
+      objSoucer: {},
+      typeList: []
+    }
+  },
+  mounted() {
+    this.getType()
+    this.getSource()
+    this.getProject()
+  },
+
+  methods: {
+    getProject() {
+      getProjectForProduct().then(res => {
+        if (res.code === 200) {
+          const data = res.data
+          if (undefined !== data.PROJECT) {
+            this.projectList = data.PROJECT
+          }
+          if (undefined !== data.SOURCE) {
+            this.objSoucer = data.SOURCE
+          }
+        }
+      })
+    },
+    projectChange(val) {
+      this.sourceList = []
+      this.searchForm.productSourceId = null
+      if (this.objSoucer[val] !== undefined) {
+        this.sourceList = this.objSoucer[val]
+      }
+    },
+    getType() {
+      debugger
+      getAllIsUseing().then(res => {
+        if (res.code === 200) {
+          this.typeList = res.data
+        }
+      })
+    },
+    getSource() {
+      getIsUseingData().then(res => {
+        if (res.code === 200) {
+          this.sourceList = res.data
+          this.sourceListBackups = res.data
+        }
+      })
+    },
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.getType()
+      this.getSource()
+      this.getProject()
+
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/product/item/index.js

@@ -0,0 +1,3 @@
+import BasicSettingProduct from './BasicSettingProductMain.vue'
+
+export default BasicSettingProduct

+ 66 - 0
src/views/basicSetting/product/item/object.js

@@ -0,0 +1,66 @@
+export const searchForm = {
+  bsProductId: null,
+  productName: null,
+  productTypeId: null,
+  productTypeName: null,
+  productSourceId: null,
+  productSourceName: null,
+  productGroupId: null,
+  productGroupName: null,
+  relationProjectId: null,
+  relationProjectName: null,
+  isUseing: null,
+  deleted: null,
+  createBy: null,
+  createTime: null,
+  updateBy: null,
+  updateTime: null,
+  remark: null
+}
+
+export class BasicSettingProductEnt {
+  bsProductId
+  productName
+  productTypeId
+  productTypeName
+  productSourceId
+  productSourceName
+  productGroupId
+  productGroupName
+  relationProjectId
+  relationProjectName
+  isUseing
+  deleted
+  createBy
+  createTime
+  updateBy
+  updateTime
+  remark
+}
+
+export const formRules = {
+  // bsProductId: [{ required: true, message: '请填写', trigger: 'change' }],
+  productName: [{ required: true, message: '请填写产品名称', trigger: 'change' }],
+  productTypeId: [{ required: true, message: '请填写产品类型id', trigger: 'change' }],
+  // productTypeName: [{ required: true, message: '请填写产品类型名称', trigger: 'change' }],
+  productSourceId: [{ required: true, message: '请填写产品来源id', trigger: 'change' }],
+  // productSourceName: [{ required: true, message: '请填写产品来源名称', trigger: 'change' }],
+  // productGroupId: [{ required: true, message: '请填写产品组id', trigger: 'change' }],
+  // productGroupName: [{ required: true, message: '请填写产品组名称', trigger: 'change' }],
+  relationProjectId: [{ required: true, message: '请填写关联项目id', trigger: 'change' }],
+  // relationProjectName: [{ required: true, message: '请填写关联项目名称', trigger: 'change' }],
+  isUseing: [{ required: true, message: '请填写是否启用', trigger: 'change' }]
+  // deleted: [{ required: true, message: '请填写逻辑删除', trigger: 'change' }],
+  // createBy: [{ required: true, message: '请填写创建者', trigger: 'change' }],
+  // createTime: [{ required: true, message: '请填写创建时间', trigger: 'change' }],
+  // updateBy: [{ required: true, message: '请填写更新者', trigger: 'change' }],
+  // updateTime: [{ required: true, message: '请填写更新时间', trigger: 'change' }],
+  // remark: [{ required: true, message: '请填写备注', trigger: 'change' }]
+}
+export const isUseingList = [{
+  value: 'ISUSEING',
+  label: '启用'
+}, {
+  value: 'ISNOTUSEING',
+  label: '不启用'
+}]

+ 150 - 0
src/views/basicSetting/product/source/BasicSettingProductSourceMain.vue

@@ -0,0 +1,150 @@
+<template>
+  <div>
+    <Search ref="search" />
+    <el-row type="flex" justify="space-between" class="operate-box">
+      <el-button type="primary" icon="el-icon-plus" round @click="showAdd">新 增</el-button>
+    </el-row>
+    <div class="table-container">
+      <el-table v-loading="loading" stripe class="list-table" :data="data">
+        <c-data-empty slot="empty" />
+        <el-table-column type="index" width="50" label="序号" align="center" />
+        <el-table-column prop="source" label="来源名称" align="center" />
+        <el-table-column prop="isUseing" label="是否启用" align="center">
+          <template slot-scope="scope">
+            <div v-if=" scope.row.isUseing==='ISUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="启用" type="success" center show-icon :closable="false" />
+            </div>
+            <div v-if=" scope.row.isUseing==='ISNOTUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="不启用" type="error" center show-icon :closable="false" />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="relationProjectName" label="关联项目名称" align="center" />
+        <el-table-column prop="rebateRatio" label="返点比例" width="150" align="center">
+          <template slot-scope="scope">
+            {{ scope.row.rebateRatio }}%
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="备注" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="createBy" label="创建者" align="center" />
+        <el-table-column prop="createTime" label="创建时间" align="center" />
+        <el-table-column prop="updateBy" label="更新者" align="center" />
+        <el-table-column prop="updateTime" label="更新时间" align="center" />
+        <el-table-column label="操作" width="100" fixed="right">
+          <template slot-scope="{row}">
+            <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+            <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <c-pagination
+      :page-size.sync="pageInfo.pageSize"
+      :page-no.sync="pageInfo.pageNum"
+      :total="pageInfo.total"
+      :get-data-fun="loadData"
+    />
+    <OptionDialog ref="dialog" />
+    <ProjectOptionDialog ref="prolog" />
+  </div>
+</template>
+
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/product/basicSettingProductSource'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+
+import ProjectOptionDialog from '../../project/OptionDialog.vue'
+import { BasicSettingProjectEnt } from '../../project/object'
+
+import { BasicSettingProductSourceEnt, isUseingList } from './object'
+export default {
+  name: 'BasicSettingProductSource',
+  components: { Search, OptionDialog, ProjectOptionDialog },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit,
+      isUseingList: isUseingList,
+      showAddProject: this.showAddProject
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      data: [],
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.data = res.data.records
+        this.pageInfo.total = res.data.total
+        this.loading = false
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.bsProductSourceId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.show(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingProductSourceEnt())
+    },
+    showAddProject() {
+      this.$refs.prolog.show(false, new BasicSettingProjectEnt())
+    }
+  }
+}
+</script>
+
+<style scoped>
+.el-alert--success.is-light {
+    background-color: #f0f9eb;
+    color: #67C23A;
+    padding: 0;
+}
+.el-alert--error.is-light {
+    background-color: #fef0f0;
+    color: #F56C6C;
+    padding: 0;
+}
+</style>

+ 165 - 0
src/views/basicSetting/product/source/OptionDialog.vue

@@ -0,0 +1,165 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="45%"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+
+      <el-form-item label="来源名称" prop="source">
+        <el-input v-model="ent.source" maxlength="30" placeholder="最大输入长度30 超出截断" />
+      </el-form-item>
+      <el-form-item label="是否启用" prop="isUseing">
+        <el-select v-model="ent.isUseing" placeholder="请选择">
+          <el-option v-for="item in isUseingList" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+
+      <el-form-item label="关联项目名称" prop="relationProjectId">
+        <el-select v-model="ent.relationProjectId" filterable placeholder="请选择" @change="selectChange">
+          <el-option
+            v-for="item in options"
+            :key="item.bsProjectId"
+            :label="item.projectName"
+            :value="item.bsProjectId"
+          />
+        </el-select>
+        <el-button class="ml-10" type="text" @click="projectAdd"><u>新增项目</u></el-button>
+        <el-tooltip class="item" effect="dark" content="刷新关联项目选择内容" placement="top-start">
+          <el-button class="ml-10" type="text" icon="el-icon-refresh" @click="refreshRest" />
+        </el-tooltip>
+      </el-form-item>
+      <el-form-item label="返点比例(%)" prop="rebateRatio">
+        <el-input v-model="ent.rebateRatio" type="number" max="100" placeholder="单位: %" />
+      </el-form-item>
+
+      <el-form-item label="备注" prop="remark" type="textarea">
+        <el-input v-model="ent.remark" type="textarea" maxlength="100" min="0" placeholder="最大输入长度100 超出截断" />
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/product/basicSettingProductSource'
+import { BasicSettingProductSourceEnt, formRules, isUseingList } from './object'
+import {
+  getProjectForSource
+} from '@/network/api/basicSetting/project/basicSettingProject'
+
+export default {
+  inject: ['loadData', 'showAddProject'],
+  data() {
+    return {
+      ent: new BasicSettingProductSourceEnt(),
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      cityList: [],
+      isUseingList: isUseingList,
+      options: []
+    }
+  },
+  mounted() {
+    this.getProject()
+  },
+  methods: {
+    refreshRest() {
+      this.getProject()
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    selectChange(val) {
+      var arr2 = this.options.filter(w => w.bsProjectId === val)
+      if (arr2.length > 0) {
+        this.ent.relationProjectName = arr2[0].projectName
+      }
+    },
+    getProject() {
+      getProjectForSource().then(x => {
+        if (x.code === 200) {
+          this.options = x.data
+        }
+      })
+    },
+    projectAdd() {
+      this.close()
+      this.showAddProject()
+    },
+    addRow() {
+      const req = { ...this.ent }
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    show(isEdit = false, ent) {
+      if (!isEdit) {
+        ent.isUseing = 'ISUSEING'
+      }
+      this.ent = ent
+      this.isEdit = isEdit
+
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空')
+        }
+      })
+    }
+  }
+}
+</script>

+ 89 - 0
src/views/basicSetting/product/source/Search.vue

@@ -0,0 +1,89 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="12">
+
+      <el-col :span="3">
+        <el-form-item prop="source">
+          <el-input v-model="searchForm.source" placeholder="来源名称" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="relationProjectName">
+          <el-input v-model="searchForm.relationProjectName" placeholder="关联项目名称" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="isUseing">
+          <el-select v-model="searchForm.isUseing" placeholder="请选择">
+            <el-option v-for="item in isUseingList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+
+      <!-- <el-col :span="6">
+        <el-form-item prop="rebateRatio">
+          <el-input v-model="searchForm.rebateRatio" placeholder="返点比例/反利率" />
+        </el-form-item>
+      </el-col> -->
+
+      <!-- <el-col :span="6">
+        <el-form-item prop="createBy">
+          <el-input v-model="searchForm.createBy" placeholder="创建者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="createTime">
+          <el-input v-model="searchForm.createTime" placeholder="创建时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateBy">
+          <el-input v-model="searchForm.updateBy" placeholder="更新者" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="updateTime">
+          <el-input v-model="searchForm.updateTime" placeholder="更新时间" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="6">
+        <el-form-item prop="remark">
+          <el-input v-model="searchForm.remark" placeholder="备注" />
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="3">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row>
+    <el-row />
+  </el-form>
+</template>
+<script>
+import { searchForm, isUseingList } from './object'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      searchForm: searchForm,
+      isUseingList: isUseingList
+    }
+  },
+  methods: {
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/product/source/index.js

@@ -0,0 +1,3 @@
+import BasicSettingProductSource from './BasicSettingProductSourceMain.vue'
+
+export default BasicSettingProductSource

+ 45 - 0
src/views/basicSetting/product/source/object.js

@@ -0,0 +1,45 @@
+export const searchForm = {
+
+  source: null,
+  isUseing: null,
+  relationProjectId: null,
+  relationProjectName: null,
+  rebateRatio: null,
+  deleted: null,
+  createBy: null,
+  createTime: null,
+  updateBy: null,
+  updateTime: null,
+  remark: null
+}
+
+export class BasicSettingProductSourceEnt {
+  source
+  isUseing
+  relationProjectId
+  relationProjectName
+  rebateRatio
+  deleted
+  createBy
+  createTime
+  updateBy
+  updateTime
+  remark
+}
+
+export const formRules = {
+
+  source: [{ required: true, message: '请填写来源名称', trigger: 'change' }],
+  isUseing: [{ required: true, message: '请填写是否启用', trigger: 'change' }],
+  relationProjectId: [{ required: true, message: '请填写关联项目名称', trigger: 'change' }],
+  rebateRatio: [{ required: true, message: '请填写返点比例/反利率', trigger: 'change' }]
+
+}
+
+export const isUseingList = [{
+  value: 'ISUSEING',
+  label: '启用'
+}, {
+  value: 'ISNOTUSEING',
+  label: '不启用'
+}]

+ 146 - 0
src/views/basicSetting/product/type/BasicSettingProductTypeMain.vue

@@ -0,0 +1,146 @@
+<template>
+  <div>
+    <Search ref="search" />
+    <el-row type="flex" justify="space-between" class="operate-box">
+      <el-button type="primary" icon="el-icon-plus" round @click="showAdd">新 增</el-button>
+    </el-row>
+    <div class="table-container">
+      <el-table v-loading="loading" stripe class="list-table" :data="data">
+        <c-data-empty slot="empty" />
+        <el-table-column type="index" width="50" label="序号" align="center" />
+        <el-table-column prop="typeName" label="品类名称" align="center" />
+        <el-table-column prop="isUseing" label="是否启用" align="center">
+          <template slot-scope="scope">
+            <div v-if=" scope.row.isUseing==='ISUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="启用" type="success" center show-icon :closable="false" />
+            </div>
+            <div v-if=" scope.row.isUseing==='ISNOTUSEING'" slot="reference" class="name-wrapper">
+              <el-alert title="不启用" type="error" center show-icon :closable="false" />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="备注" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="createBy" label="创建者" align="center" />
+        <el-table-column prop="createTime" label="创建时间" align="center" />
+        <el-table-column prop="updateBy" label="更新者" align="center" />
+        <el-table-column prop="updateTime" label="更新时间" align="center" />
+
+        <el-table-column label="操作" width="100">
+          <template slot-scope="{row}">
+            <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+            <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <c-pagination
+      :page-size.sync="pageInfo.pageSize"
+      :page-no.sync="pageInfo.pageNum"
+      :total="pageInfo.total"
+      :get-data-fun="loadData"
+    />
+    <OptionDialog ref="dialog" />
+  </div>
+</template>
+
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/product/basicSettingProductType'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+import { BasicSettingProductTypeEnt } from './object'
+export default {
+  name: 'BasicSettingProductType',
+  components: { Search, OptionDialog },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      data: [],
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      debugger
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.loading = false
+        if (res.code === 200) {
+          this.data = res.data.records
+          this.pageInfo.total = res.data.total
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+          this.data = []
+          this.pageInfo.total = 0
+        }
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.bsProductTypeId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.show(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingProductTypeEnt())
+    }
+  }
+}
+</script>
+
+<style scoped>
+.el-alert--success.is-light {
+    background-color: #f0f9eb;
+    color: #67C23A;
+    padding: 0;
+}
+.el-alert--error.is-light {
+    background-color: #fef0f0;
+    color: #F56C6C;
+    padding: 0;
+}
+</style>

+ 117 - 0
src/views/basicSetting/product/type/OptionDialog.vue

@@ -0,0 +1,117 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="45%"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+      <el-form-item label="品类名称" prop="typeName">
+        <el-input v-model="ent.typeName" maxlength="30" placeholder="最大输入长度30 超出截断" />
+      </el-form-item>
+      <el-form-item label="是否启用" prop="isUseing">
+        <el-select v-model="ent.isUseing" placeholder="请选择">
+          <el-option v-for="item in isUseingList" :key="item.value" :label="item.label" :value="item.value" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="ent.remark" type="textarea" maxlength="100" placeholder="最大输入长度100 超出截断" />
+      </el-form-item>
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/product/basicSettingProductType'
+import { BasicSettingProductTypeEnt, formRules, isUseingList } from './object'
+
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      ent: new BasicSettingProductTypeEnt(),
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      cityList: [],
+      isUseingList: isUseingList
+    }
+  },
+  methods: {
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    show(isEdit = false, ent) {
+      if (!isEdit) {
+        ent.isUseing = 'ISUSEING'
+      }
+      this.ent = ent
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空!')
+        }
+      })
+    }
+  }
+}
+</script>

+ 51 - 0
src/views/basicSetting/product/type/Search.vue

@@ -0,0 +1,51 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="24">
+
+      <el-col :span="3">
+        <el-form-item prop="typeName">
+          <el-input v-model="searchForm.typeName" placeholder="品类名称" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="isUseing">
+          <el-select v-model="searchForm.isUseing" placeholder="是否启用">
+            <el-option v-for="item in isUseingList" :key="item.value" :label="item.label" :value="item.value" />
+          </el-select>
+
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row></el-form>
+</template>
+<script>
+import { searchForm, isUseingList } from './object'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      searchForm: searchForm,
+      isUseingList: isUseingList
+    }
+  },
+  methods: {
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/product/type/index.js

@@ -0,0 +1,3 @@
+import BasicSettingProductType from './BasicSettingProductTypeMain.vue'
+
+export default BasicSettingProductType

+ 25 - 0
src/views/basicSetting/product/type/object.js

@@ -0,0 +1,25 @@
+export const searchForm = {
+  typeName: null,
+  isUseing: null,
+  remark: null
+}
+
+export class BasicSettingProductTypeEnt {
+  typeName
+  isUseing
+  remark
+}
+
+export const formRules = {
+  typeName: [{ required: true, message: '请填写品类名称', trigger: 'change' }],
+  isUseing: [{ required: true, message: '请填写是否启用', trigger: 'change' }]
+
+}
+
+export const isUseingList = [{
+  value: 'ISUSEING',
+  label: '启用'
+}, {
+  value: 'ISNOTUSEING',
+  label: '不启用'
+}]

+ 142 - 0
src/views/basicSetting/project/BasicSettingProjectMain.vue

@@ -0,0 +1,142 @@
+<template>
+  <div>
+    <Search ref="search" />
+    <el-row type="flex" justify="space-between" class="operate-box">
+      <el-button type="primary" icon="el-icon-plus" round @click="showAdd">新 增</el-button>
+    </el-row>
+    <div class="table-container">
+      <el-table v-loading="loading" stripe class="list-table" :data="data">
+        <c-data-empty slot="empty" />
+
+        <el-table-column type="index" width="50" label="序号" align="center" />
+
+        <el-table-column prop="projectName" label="项目名称" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="leaderUserName" label="项目负责人" align="center" :show-overflow-tooltip="true" />
+        <el-table-column prop="projectVisibleType" label="可见状态" align="center" />
+        <el-table-column prop="visibleUserIdListName" label="项目可见人员" align="center" :show-overflow-tooltip="true" />
+        <!-- <el-table-column prop="visibleUserIdList" label="可见人员结合" align="center" />  可见状态/ALL:全员/PART:部分-->
+        <el-table-column prop="status" label="可用状态" align="center">
+          <template slot-scope="scope">
+            <div v-if=" scope.row.status==='可用'" slot="reference" class="name-wrapper">
+              <el-alert title="可用" type="success" center show-icon :closable="false" />
+            </div>
+            <div v-if=" scope.row.status==='不可用'" slot="reference" class="name-wrapper">
+              <el-alert title="不可用" type="error" center show-icon :closable="false" />
+            </div>
+          </template>
+        </el-table-column>
+        <el-table-column prop="remark" label="备注" align="center" :show-overflow-tooltip="true" />
+
+        <el-table-column prop="createBy" label="创建者" align="center" />
+        <el-table-column prop="createTime" label="创建时间" width="150" align="center" />
+
+        <el-table-column prop="updateBy" label="更新者" align="center" />
+        <el-table-column prop="updateTime" label="更新时间" width="150" align="center" />
+        <el-table-column label="操作" width="100">
+          <template slot-scope="{row}">
+            <el-button type="text" size="small" @click="showEdit(row)">编辑</el-button>
+            <el-button type="text" size="small" @click="deleteRow(row)">删除</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <c-pagination
+      :page-size.sync="pageInfo.pageSize"
+      :page-no.sync="pageInfo.pageNum"
+      :total="pageInfo.total"
+      :get-data-fun="loadData"
+    />
+    <OptionDialog ref="dialog" />
+  </div>
+</template>
+
+<script>
+import { PageCommonComponent } from '@/common/mixin'
+import {
+  Page,
+  Delete
+} from '@/network/api/basicSetting/project/basicSettingProject'
+import Search from './Search'
+import OptionDialog from './OptionDialog'
+import { BasicSettingProjectEnt } from './object'
+export default {
+  name: 'BasicSettingProject',
+  components: { Search, OptionDialog },
+  mixins: [PageCommonComponent],
+  provide: function () {
+    return {
+      loadData: this.loadData,
+      showEdit: this.showEdit
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      data: [],
+      pageInfo: {
+        pageNum: 1,
+        pageSize: 10,
+        total: 0
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData(isFirst = false) {
+      const searchForm = this.$refs.search.getSearchForm()
+      this.doLoadData(isFirst, searchForm)
+    },
+    doLoadData(firstPage = false, searchForm) {
+      firstPage && (this.pageInfo.pageNum = 1)
+      const req = { ...searchForm, ...this.pageInfo }
+      this.loading = true
+      Page(req).then(res => {
+        this.data = res.data.records
+        this.pageInfo.total = res.data.total
+        this.loading = false
+      })
+    },
+    deleteRow(row) {
+      this.$confirm('确定删除, 是否继续?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        Delete(row.bsProjectId).then(res => {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.loadData()
+        })
+      }).catch(() => {
+        this.$message({
+          type: 'info',
+          message: '已取消删除'
+        })
+      })
+    },
+    showEdit(row) {
+      this.$refs.dialog.showE(true, { ...row })
+    },
+    showAdd() {
+      this.$refs.dialog.show(false, new BasicSettingProjectEnt())
+    }
+  }
+}
+</script>
+
+<style scoped>
+.el-alert--success.is-light {
+    background-color: #f0f9eb;
+    color: #67C23A;
+    padding: 0;
+}
+.el-alert--error.is-light {
+    background-color: #fef0f0;
+    color: #F56C6C;
+    padding: 0;
+}
+</style>

+ 290 - 0
src/views/basicSetting/project/OptionDialog.vue

@@ -0,0 +1,290 @@
+<template>
+  <el-dialog
+    :title="isEdit ? '编 辑': '新 增'"
+    width="1040px"
+    :visible.sync="visible"
+    :before-close="close"
+    label-position="right"
+    :modal-append-to-body="false"
+    :close-on-press-escape="false"
+    :close-on-click-modal="false"
+  >
+    <el-form ref="ent" :model="ent" :rules="rules" label-width="110px">
+      <!-- <el-form-item label="" prop="bsProjectId">
+        <el-input v-model="ent.bsProjectId" />
+      </el-form-item> -->
+      <el-form-item label="项目名称" prop="projectName">
+        <el-input v-model="ent.projectName" maxlength="30" placeholder="最大输入长度30 超出截断" />
+      </el-form-item>
+      <el-form-item label="可用状态" prop="status">
+        <el-radio-group v-model="ent.status">
+          <el-radio-button label="可用" />
+          <el-radio-button label="不可用" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item label="项目负责人" prop="leaderUserId">
+        <el-select
+          v-model="ent.leaderUserIdWeb"
+
+          filterable
+          default-first-option
+          placeholder="请选择"
+        >
+          <el-option
+            v-for="item in options"
+            :key="item.key"
+            :label="item.label"
+            :value="item.key"
+          />
+        </el-select>
+
+        <!-- <el-input v-model="ent.leaderUserId" /> -->
+      </el-form-item>
+      <el-form-item label="备注" prop="remark">
+        <el-input v-model="ent.remark" maxlength="100" type="textarea" placeholder="最大输入长度100 超出截断" />
+      </el-form-item>
+
+      <el-form-item label="可见状态" prop="projectVisibleType">
+        <el-radio-group v-model="ent.projectVisibleType" @change="radioChange">
+          <el-radio-button label="全员可见" />
+          <el-radio-button label="指定人员" />
+        </el-radio-group>
+      </el-form-item>
+      <el-form-item v-if="visibleTransfer" prop="remark">
+        <div class="edit_dev">
+          <el-transfer
+            v-model="ent.visibleUserIdListWeb"
+            :titles="['待选择', '已选择']"
+            filterable
+            filter-placeholder="请输入"
+            :data="options"
+          />
+        </div>
+      </el-form-item>
+
+      <!-- <el-form-item label="可见状态/ALL:全员/PART:部分" prop="projectVisibleType">
+        <el-input v-model="ent.projectVisibleType" />
+      </el-form-item> -->
+      <!-- <el-form-item label="可见人员结合" prop="visibleUserIdList">
+        <el-input v-model="ent.visibleUserIdList" />
+      </el-form-item> -->
+      <!-- <el-form-item label="状态/ISUSEING、INNOTUSEING" prop="status">
+        <el-input v-model="ent.status" />
+      </el-form-item>
+      <el-form-item label="逻辑删除" prop="deleted">
+        <el-input v-model="ent.deleted" />
+      </el-form-item>
+      <el-form-item label="创建者" prop="createBy">
+        <el-input v-model="ent.createBy" />
+      </el-form-item>
+      <el-form-item label="创建时间" prop="createTime">
+        <el-input v-model="ent.createTime" />
+      </el-form-item>
+      <el-form-item label="更新者" prop="updateBy">
+        <el-input v-model="ent.updateBy" />
+      </el-form-item>
+      <el-form-item label="更新时间" prop="updateTime">
+        <el-input v-model="ent.updateTime" />
+      </el-form-item> -->
+
+    </el-form>
+    <span slot="footer" class="dialog-footer">
+      <el-button round @click="close">取消</el-button>
+      <el-popconfirm class="ml-10" confirm-button-text="提交" cancel-button-text="取消" icon="el-icon-info" icon-color="red" title="确定提交?" @confirm="submit">
+        <el-button slot="reference" type="primary" round>确定</el-button>
+      </el-popconfirm>
+    </span>
+  </el-dialog>
+</template>
+<script>
+import {
+  Add,
+  Update
+} from '@/network/api/basicSetting/project/basicSettingProject'
+
+import { getUser } from '@/network/api/user'
+import { BasicSettingProjectEnt, formRules } from './object'
+
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      ent: new BasicSettingProjectEnt(),
+      rules: formRules,
+      isEdit: false,
+      visible: false,
+      cityList: [],
+      options: [],
+      visibleTransfer: false
+    }
+  },
+  mounted() {
+    this.getUserList()
+  },
+  methods: {
+
+    radioChange() {
+      const VisibleType = this.ent.projectVisibleType
+      if (VisibleType === '全员可见') {
+        this.visibleTransfer = false
+        if (!this.isEdit) {
+          this.ent.visibleUserIdListWeb = []
+        }
+      } else {
+        this.visibleTransfer = true
+      }
+    },
+    getUserList() {
+      getUser().then(res => {
+        if (res.code === 200) {
+          this.options = res.data
+        }
+      })
+    },
+    submit() {
+      this.$refs.ent.validate((validate) => {
+        if (validate) {
+          if (this.ent.projectVisibleType === '指定人员') {
+            if (undefined === this.ent.visibleUserIdListWeb || this.ent.visibleUserIdListWeb.length === 0) {
+              this.$message({
+                message: '请选择指定人员',
+                type: 'error'
+              })
+              return
+            }
+          }
+          if ((undefined !== this.ent.leaderUserIdWeb || undefined !== this.ent.visibleUserIdListWeb) && undefined !== this.options) {
+            if (undefined !== this.ent.leaderUserIdWeb) {
+              // this.ent.leaderUserIdWeb.forEach(x => {
+              //   this.options.forEach(w => {
+              //     if (w.key === x) {
+              //       this.ent.leaderUserName = this.ent.leaderUserName === undefined ? w.label : this.ent.leaderUserName + ',' + w.label
+              //     }
+              //   })
+              // })
+              this.ent.leaderUserId = this.ent.leaderUserIdWeb
+              this.options.forEach(item => {
+                if (item.key === this.ent.leaderUserId) {
+                  this.ent.leaderUserName = item.label
+                }
+              })
+            }
+            if (undefined !== this.ent.visibleUserIdListWeb) {
+              this.ent.visibleUserIdListWeb.forEach(x => {
+                this.options.forEach(w => {
+                  if (w.key === x) {
+                    this.ent.visibleUserIdListName = this.ent.visibleUserIdListName === undefined || this.ent.visibleUserIdListName === null ? w.label : this.ent.visibleUserIdListName + ',' + w.label
+                  }
+                })
+              })
+              this.ent.visibleUserIdList = this.ent.visibleUserIdListWeb.toString()
+            }
+          }
+          this.isEdit ? this.updateRow() : this.addRow()
+        }
+      })
+    },
+    addRow() {
+      const req = { ...this.ent }
+      Add(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    updateRow() {
+      const req = { ...this.ent }
+      Update(req).then(res => {
+        if (res.code === 200) {
+          this.$message({
+            message: res.msg,
+            type: 'success'
+          })
+          this.loadData()
+          this.close()
+        } else {
+          this.$message({
+            message: res.msg,
+            type: 'error'
+          })
+        }
+      })
+    },
+    close() {
+      this.visible = false
+      this.$nextTick(() => {
+        this.$refs.ent.resetFields()
+      })
+    },
+    show(isEdit = false, ent) {
+      this.ent = ent
+      if (undefined === ent.projectVisibleType) {
+        this.ent.projectVisibleType = '全员可见'
+        this.visibleTransfer = false
+      }
+      if (undefined === ent.status) {
+        this.ent.status = '可用'
+      }
+
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          console.log('不能为空!')
+        }
+      })
+    },
+
+    showE(isEdit = false, ent) {
+      this.ent = new BasicSettingProjectEnt()
+      this.ent.bsProjectId = ent.bsProjectId
+      this.ent.projectName = ent.projectName
+      this.ent.projectVisibleType = ent.projectVisibleType
+      this.ent.status = ent.status
+      this.ent.remark = ent.remark
+
+      if (undefined === ent.projectVisibleType) {
+        this.ent.projectVisibleType = '全员可见'
+        this.visibleTransfer = false
+      }
+      if (undefined === ent.status) {
+        this.ent.status = '可用'
+      }
+
+      if (ent.projectVisibleType === '指定人员') {
+        this.visibleTransfer = true
+        if (undefined !== ent.visibleUserIdList) {
+          this.ent.visibleUserIdListWeb = ent.visibleUserIdList.split(',')
+        }
+      }
+      if (undefined !== ent.leaderUserId) {
+        this.ent.leaderUserIdWeb = ent.leaderUserId
+      }
+
+      this.isEdit = isEdit
+      this.visible = true
+      this.$nextTick(() => {
+        if (this.isEdit) {
+          this.ent.visibleUserIdListName = undefined
+          this.ent.leaderUserName = undefined
+        }
+      })
+    }
+  }
+}
+</script>
+<style scoped>
+   .edit_dev >>> .el-transfer-panel {
+     width:300px;
+   }
+</style>

+ 97 - 0
src/views/basicSetting/project/Search.vue

@@ -0,0 +1,97 @@
+<template>
+  <el-form ref="searchForm" class="search-form" :model="searchForm">
+    <el-row :gutter="12">
+
+      <el-col :span="3">
+        <el-form-item prop="projectName">
+          <el-input v-model="searchForm.projectName" placeholder="项目名称" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="leaderUserName">
+          <el-input v-model="searchForm.leaderUserName" placeholder="项目负责人" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="3">
+        <el-form-item prop="visibleUserIdListName">
+          <el-input v-model="searchForm.visibleUserIdListName" placeholder="项目可见人员" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="projectVisibleType">
+          <el-select v-model="searchForm.projectVisibleType" placeholder="可见状态">
+            <el-option label="全员可见" value="ALL" />
+            <el-option label="指定人员" value="PART" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="status">
+          <el-select v-model="searchForm.status" placeholder="可用状态">
+            <el-option label="可用" value="1" />
+            <el-option label="不可能" value="0" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="3">
+        <el-form-item prop="createBy">
+          <el-input v-model="searchForm.createBy" placeholder="创建者" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+      <!-- <el-col :span="6">
+        <el-form-item prop="createTime">
+          <el-input v-model="searchForm.createTime" placeholder="创建时间" />
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="3">
+        <el-form-item prop="updateBy">
+          <el-input v-model="searchForm.updateBy" placeholder="更新者" @keyup.enter.native="search" />
+        </el-form-item>
+      </el-col>
+
+      <!-- <el-col :span="6">
+        <el-form-item prop="updateTime">
+          <el-input v-model="searchForm.updateTime" placeholder="更新时间" />
+        </el-form-item>
+      </el-col> -->
+      <!-- <el-col :span="6">
+        <el-form-item prop="remark">
+          <el-input v-model="searchForm.remark" placeholder="备注" />
+        </el-form-item>
+      </el-col> -->
+      <el-col :span="3">
+        <el-button class="btn" type="primary" @click="search">
+          查询
+        </el-button>
+        <el-button class="btn" @click="resetSearch">
+          重置
+        </el-button>
+      </el-col>
+    </el-row>
+
+  </el-form>
+</template>
+<script>
+import { searchForm } from './object'
+export default {
+  inject: ['loadData'],
+  data() {
+    return {
+      searchForm: searchForm
+    }
+  },
+  methods: {
+    search() {
+      this.loadData(true)
+    },
+    // 折中方案
+    getSearchForm() {
+      return { ...this.searchForm }
+    },
+    resetSearch() {
+      this.$refs.searchForm.resetFields()
+    }
+  }
+}
+</script>

+ 3 - 0
src/views/basicSetting/project/index.js

@@ -0,0 +1,3 @@
+import BasicSettingProject from './BasicSettingProjectMain.vue'
+
+export default BasicSettingProject

+ 48 - 0
src/views/basicSetting/project/object.js

@@ -0,0 +1,48 @@
+export const searchForm = {
+
+  projectName: null,
+  leaderUserId: null,
+  projectVisibleType: null,
+  visibleUserIdList: null,
+  status: null,
+  deleted: null,
+  createBy: null,
+  createTime: null,
+  updateBy: null,
+  updateTime: null,
+  remark: null
+}
+
+export class BasicSettingProjectEnt {
+  bsProjectId
+  projectName
+  leaderUserIdWeb
+  leaderUserId
+  leaderUserName
+  projectVisibleType
+  visibleUserIdListWeb
+  visibleUserIdList
+  visibleUserIdListName
+  status
+  deleted
+  createBy
+  createTime
+  updateBy
+  updateTime
+  remark
+}
+
+export const formRules = {
+  // bsProjectId: [{ required: true, message: '请填写', trigger: 'change' }],
+  projectName: [{ required: true, message: '请填写项目名称', trigger: 'change' }]
+  // leaderUserId: [{ required: true, message: '请填写项目负责人', trigger: 'change' }],
+  // projectVisibleType: [{ required: true, message: '请填写可见状态/ALL:全员/PART:部分', trigger: 'change' }],
+  // visibleUserIdList: [{ required: true, message: '请填写可见人员结合', trigger: 'change' }],
+  // status: [{ required: true, message: '请填写状态/ISUSEING、INNOTUSEING', trigger: 'change' }],
+  // deleted: [{ required: true, message: '请填写逻辑删除', trigger: 'change' }],
+  // createBy: [{ required: true, message: '请填写创建者', trigger: 'change' }],
+  // createTime: [{ required: true, message: '请填写创建时间', trigger: 'change' }],
+  // updateBy: [{ required: true, message: '请填写更新者', trigger: 'change' }],
+  // updateTime: [{ required: true, message: '请填写更新时间', trigger: 'change' }],
+  // remark: [{ required: true, message: '请填写备注', trigger: 'change' }]
+}

+ 422 - 0
src/views/dict/data.vue

@@ -0,0 +1,422 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" class="search-form" :model="queryParams" :inline="true" label-width="68px">
+      <el-form-item label="" prop="dictType">
+        <el-select v-model="queryParams.dictType" size="small">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.dictId"
+            :label="item.dictName"
+            :value="item.dictType"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="" prop="dictLabel">
+        <el-input
+          v-model="queryParams.dictLabel"
+          placeholder="请输入字典标签"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="" prop="status">
+        <el-select v-model="queryParams.status" placeholder="数据状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8 justify-left">
+
+      <el-button
+        round
+        type="primary"
+        plain
+        icon="el-icon-plus"
+        size="mini"
+        @click="handleAdd"
+      >新增</el-button>
+
+      <el-button
+        round
+        type="success"
+        plain
+        icon="el-icon-edit"
+        size="mini"
+        :disabled="single"
+        @click="handleUpdate"
+      >修改</el-button>
+
+      <el-button
+        round
+        type="danger"
+        plain
+        icon="el-icon-delete"
+        size="mini"
+        :disabled="multiple"
+        @click="handleDelete"
+      >删除</el-button>
+
+      <el-button
+        round
+        type="warning"
+        plain
+        icon="el-icon-download"
+        size="mini"
+        @click="handleExport"
+      >导出</el-button>
+
+      <right-toolbar class="ml-10" :show-search.sync="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="字典编码" align="center" prop="dictCode" />
+      <el-table-column label="字典标签" align="center" prop="dictLabel">
+        <template slot-scope="scope">
+          <span v-if="scope.row.listClass == '' || scope.row.listClass == 'default'">{{ scope.row.dictLabel }}</span>
+          <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass">{{ scope.row.dictLabel }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="字典键值" align="center" prop="dictValue" />
+      <el-table-column label="字典排序" align="center" prop="dictSort" />
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            round
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+          >修改</el-button>
+          <el-button
+            round
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改参数配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="字典类型">
+          <el-input v-model="form.dictType" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="数据标签" prop="dictLabel">
+          <el-input v-model="form.dictLabel" placeholder="请输入数据标签" />
+        </el-form-item>
+        <el-form-item label="数据键值" prop="dictValue">
+          <el-input v-model="form.dictValue" placeholder="请输入数据键值" />
+        </el-form-item>
+        <el-form-item label="样式属性" prop="cssClass">
+          <el-input v-model="form.cssClass" placeholder="请输入样式属性" />
+        </el-form-item>
+        <el-form-item label="显示排序" prop="dictSort">
+          <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="回显样式" prop="listClass">
+          <el-select v-model="form.listClass">
+            <el-option
+              v-for="item in listClassOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{ dict.dictLabel }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" round @click="submitForm">确 定</el-button>
+        <el-button round @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listData, getData, delData, addData, updateData } from '@/network/api/system/dict/data'
+import { listType, getType } from '@/network/api/system/dict/type'
+
+export default {
+  name: 'Data',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 字典表格数据
+      dataList: [],
+      // 默认字典类型
+      defaultDictType: '',
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      // 数据标签回显样式
+      listClassOptions: [
+        {
+          value: 'default',
+          label: '默认'
+        },
+        {
+          value: 'primary',
+          label: '主要'
+        },
+        {
+          value: 'success',
+          label: '成功'
+        },
+        {
+          value: 'info',
+          label: '信息'
+        },
+        {
+          value: 'warning',
+          label: '警告'
+        },
+        {
+          value: 'danger',
+          label: '危险'
+        }
+      ],
+      // 状态数据字典
+      statusOptions: [],
+      // 类型数据字典
+      typeOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictName: undefined,
+        dictType: undefined,
+        status: undefined
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        dictLabel: [
+          { required: true, message: '数据标签不能为空', trigger: 'blur' }
+        ],
+        dictValue: [
+          { required: true, message: '数据键值不能为空', trigger: 'blur' }
+        ],
+        dictSort: [
+          { required: true, message: '数据顺序不能为空', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+    const dictId = this.$route.params && this.$route.params.dictId
+    this.getType(dictId)
+    this.getTypeList()
+    this.getDicts('sys_normal_disable').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询字典类型详细 */
+    getType(dictId) {
+      getType(dictId).then(response => {
+        this.queryParams.dictType = response.data.dictType
+        this.defaultDictType = response.data.dictType
+        this.getList()
+      })
+    },
+    /** 查询字典类型列表 */
+    getTypeList() {
+      listType().then(response => {
+        this.typeOptions = response.rows
+      })
+    },
+    /** 查询字典数据列表 */
+    getList() {
+      this.loading = true
+      listData(this.queryParams).then(response => {
+        this.dataList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        dictCode: undefined,
+        dictLabel: undefined,
+        dictValue: undefined,
+        cssClass: undefined,
+        listClass: 'default',
+        dictSort: 0,
+        status: '0',
+        remark: undefined
+      }
+      this.resetForm('form')
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.queryParams.dictType = this.defaultDictType
+      this.handleQuery()
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '添加字典数据'
+      this.form.dictType = this.queryParams.dictType
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictCode)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const dictCode = row.dictCode || this.ids
+      getData(dictCode).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改字典数据'
+      })
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.dictCode !== undefined) {
+            updateData(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message({
+                  message: '修改成功',
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message({
+                  message: response.msg,
+                  type: 'error'
+                })
+              }
+            })
+          } else {
+            addData(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message({
+                  message: '新增成功',
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message({
+                  message: response.msg,
+                  type: 'error'
+                })
+              }
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const dictCodes = row.dictCode || this.ids
+      this.$confirm('是否确认删除字典编码为"' + dictCodes + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delData(dictCodes)
+      }).then(response => {
+        if (response.code === 200) {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+
+          this.getList()
+        } else {
+          this.$message({
+            message: response.msg,
+            type: 'error'
+          })
+        }
+      }).catch(() => {})
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('/api/system/dict/data/export', {
+        ...this.queryParams
+      }, `data_${new Date().getTime()}.xlsx`)
+    }
+  }
+}
+</script>

+ 391 - 0
src/views/dict/index.vue

@@ -0,0 +1,391 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" class="search-form" :model="queryParams" :inline="true" label-width="68px">
+      <el-form-item label="" prop="dictName">
+        <el-input
+          v-model="queryParams.dictName"
+          placeholder="请输入字典名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="" prop="dictType">
+        <el-input
+          v-model="queryParams.dictType"
+          placeholder="请输入字典类型"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="字典状态"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8 justify-left">
+
+      <el-button
+        round
+        type="primary"
+        plain
+        icon="el-icon-plus"
+        size="mini"
+        @click="handleAdd"
+      >新增</el-button>
+
+      <el-button
+        round
+        type="success"
+        plain
+        icon="el-icon-edit"
+        size="mini"
+        :disabled="single"
+        @click="handleUpdate"
+      >修改</el-button>
+
+      <el-button
+        round
+        type="danger"
+        plain
+        icon="el-icon-delete"
+        size="mini"
+        :disabled="multiple"
+        @click="handleDelete"
+      >删除</el-button>
+
+      <el-button
+        round
+        type="warning"
+        plain
+        icon="el-icon-download"
+        size="mini"
+        @click="handleExport"
+      >导出</el-button>
+
+      <el-button
+        round
+        type="danger"
+        plain
+        icon="el-icon-refresh"
+        size="mini"
+        @click="handleRefreshCache"
+      >刷新缓存</el-button>
+
+      <right-toolbar class="ml-10" :show-search.sync="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="字典编号" align="center" prop="dictId" />
+      <el-table-column label="字典名称" align="center" prop="dictName" :show-overflow-tooltip="true" />
+      <el-table-column label="字典类型" align="center" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <router-link :to="'dict-data/' + scope.row.dictId" class="link-type">
+            <span>{{ scope.row.dictType }}</span>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="状态" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="statusOptions" :value="scope.row.status" />
+        </template>
+      </el-table-column>
+      <el-table-column label="备注" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="创建时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            round
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+          >修改</el-button>
+          <el-button
+            round
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <paginations
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改参数配置对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="字典名称" prop="dictName">
+          <el-input v-model="form.dictName" placeholder="请输入字典名称" />
+        </el-form-item>
+        <el-form-item label="字典类型" prop="dictType">
+          <el-input v-model="form.dictType" placeholder="请输入字典类型" />
+        </el-form-item>
+        <el-form-item label="状态" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{ dict.dictLabel }}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="备注" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button round type="primary" @click="submitForm">确 定</el-button>
+        <el-button round @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listType, getType, delType, addType, updateType, refreshCache } from '@/network/api/system/dict/type'
+
+export default {
+  name: 'Dict',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 字典表格数据
+      typeList: [],
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      // 状态数据字典
+      statusOptions: [],
+      // 日期范围
+      dateRange: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictName: undefined,
+        dictType: undefined,
+        operTimeQuery: undefined,
+        status: undefined
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+        dictName: [
+          { required: true, message: '字典名称不能为空', trigger: 'blur' }
+        ],
+        dictType: [
+          { required: true, message: '字典类型不能为空', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+    this.getList()
+    this.getDicts('sys_normal_disable').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询字典类型列表 */
+    getList() {
+      if (this.dateRange.length === 2) {
+        var zreo = this.dateRange[0]
+        var one = this.dateRange[1]
+        this.queryParams.operTimeQuery = zreo + ',' + one
+      }
+      this.loading = true
+      listType(this.queryParams).then(response => {
+        this.typeList = response.rows
+        this.total = response.total
+        this.loading = false
+      }
+      )
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        dictId: undefined,
+        dictName: undefined,
+        dictType: undefined,
+        status: '0',
+        remark: undefined
+      }
+      this.resetForm('form')
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.queryParams.operTimeQuery = undefined
+      this.dateRange = []
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.title = '添加字典类型'
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictId)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const dictId = row.dictId || this.ids
+      getType(dictId).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改字典类型'
+      })
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.dictId !== undefined) {
+            updateType(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message({
+                  message: '修改成功',
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message({
+                  message: response.msg,
+                  type: 'error'
+                })
+              }
+            })
+          } else {
+            addType(this.form).then(response => {
+              if (response.code === 200) {
+                this.$message({
+                  message: '新增成功',
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message({
+                  message: response.msg,
+                  type: 'error'
+                })
+              }
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const dictIds = row.dictId || this.ids
+      this.$confirm('是否确认删除字典编号为"' + dictIds + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delType(dictIds)
+      }).then(response => {
+        if (response.code === 200) {
+          this.$message({
+            message: '删除成功',
+            type: 'success'
+          })
+          this.getList()
+        } else {
+          this.$message({
+            message: response.msg,
+            type: 'error'
+          })
+        }
+      }).catch(() => {})
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('/api/system/dict/type/export', {
+        ...this.queryParams
+      }, `type_${new Date().getTime()}.xlsx`)
+    },
+    /** 刷新缓存按钮操作 */
+    handleRefreshCache() {
+      refreshCache().then(() => {
+        this.$message('刷新成功')
+      })
+    }
+  }
+}
+</script>

+ 0 - 0
src/views/dict/DictMain.vue → src/views/dictOld/DictMain.vue


+ 0 - 0
src/views/dict/OptionDialog.vue → src/views/dictOld/OptionDialog.vue


+ 0 - 0
src/views/dict/Search.vue → src/views/dictOld/Search.vue


+ 0 - 0
src/views/dict/index.js → src/views/dictOld/index.js


+ 0 - 0
src/views/dict/object.js → src/views/dictOld/object.js


+ 605 - 0
src/views/job/index.vue

@@ -0,0 +1,605 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" class="search-form" :model="queryParams" :inline="true" label-width="68px">
+      <el-form-item prop="jobName">
+        <el-input
+          v-model="queryParams.jobName"
+          placeholder="任务名称"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+
+      <el-form-item prop="jobGroup">
+        <el-select v-model="queryParams.jobGroup" placeholder="任务组名" clearable size="small">
+          <el-option
+            v-for="dict in jobGroupOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item prop="status">
+        <el-select v-model="queryParams.status" placeholder="任务状态" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" round size="mini" @click="handleQuery">查询</el-button>
+        <el-button icon="el-icon-refresh" size="mini" round @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="justify-left ">
+
+      <el-button
+        type="primary"
+        plain
+        round
+        icon="el-icon-plus"
+        size="mini"
+        @click="handleAdd"
+      >新增</el-button>
+      <el-button
+
+        type="success"
+        plain
+        round
+        icon="el-icon-edit"
+        size="mini"
+        :disabled="single"
+        @click="handleUpdate"
+      >修改</el-button>
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          round
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+        >新增</el-button>
+      </el-col> -->
+
+      <!-- <el-col :span="1.5">
+        <el-button
+
+          type="success"
+          plain
+          round
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+        >修改</el-button>
+      </el-col> -->
+      <el-button
+
+        type="danger"
+        plain
+        round
+        icon="el-icon-delete"
+        size="mini"
+        :disabled="multiple"
+        @click="handleDelete"
+      >删除</el-button>
+      <!-- <el-col :span="1.5">
+        <el-button
+
+          type="danger"
+          plain
+          round
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+        >删除</el-button>
+      </el-col> -->
+      <!-- <el-col :span="1.5">
+        <el-button
+
+          type="warning"
+          plain
+          round
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+        >导出</el-button>
+      </el-col> -->
+      <!-- <el-button
+
+        type="info"
+        plain
+        round
+        icon="el-icon-s-operation"
+        size="mini"
+        @click="handleJobLog"
+      >日志</el-button> -->
+      <!-- <el-col :span="1.5">
+        <el-button
+
+          type="info"
+          plain
+          round
+          icon="el-icon-s-operation"
+          size="mini"
+          @click="handleJobLog"
+        >日志</el-button>
+      </el-col> -->
+      <right-toolbar class="ml-5" :show-search.sync="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="任务编号" align="center" prop="jobId" />
+      <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
+      <el-table-column label="任务组名" align="center" prop="jobGroup" :formatter="jobGroupFormat" />
+      <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+      <el-table-column label="cron执行表达式" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
+      <el-table-column label="状态" align="center">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            active-value="0"
+            inactive-value="1"
+            @change="handleStatusChange(scope.row)"
+          />
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+          >修改</el-button>
+          <el-button
+
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+          >删除</el-button>
+          <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)">
+            <span class="el-dropdown-link " style="color: #409EFF;font-size: 12px;margin-left: 10px;">
+              <i class="el-icon-d-arrow-right " />更多
+            </span>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item
+
+                command="handleRun"
+                icon="el-icon-caret-right"
+              >执行一次</el-dropdown-item>
+              <el-dropdown-item
+
+                command="handleView"
+                icon="el-icon-view"
+              >任务详细</el-dropdown-item>
+              <el-dropdown-item
+
+                command="handleJobLog"
+                icon="el-icon-s-operation"
+              >调度日志</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <paginations
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改定时任务对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="任务名称" prop="jobName">
+              <el-input v-model="form.jobName" placeholder="请输入任务名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="任务分组" prop="jobGroup">
+              <el-select v-model="form.jobGroup" placeholder="请选择">
+                <el-option
+                  v-for="dict in jobGroupOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item prop="invokeTarget">
+              <span slot="label">
+                调用方法
+                <el-tooltip placement="top">
+                  <div slot="content">
+                    Bean调用示例:ryTask.ryParams('ry')
+                    <br>Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
+                    <br>参数说明:支持字符串,布尔类型,长整型,浮点型,整型
+                  </div>
+                  <i class="el-icon-question" />
+                </el-tooltip>
+              </span>
+              <el-input v-model="form.invokeTarget" placeholder="请输入调用目标字符串" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="cron表达式" prop="cronExpression">
+              <el-input v-model="form.cronExpression" placeholder="请输入cron执行表达式" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="是否并发" prop="concurrent">
+              <el-radio-group v-model="form.concurrent" size="small">
+                <el-radio-button label="0">允许</el-radio-button>
+                <el-radio-button label="1">禁止</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="错误策略" prop="misfirePolicy">
+              <el-radio-group v-model="form.misfirePolicy" size="small">
+                <el-radio-button label="1">立即执行</el-radio-button>
+                <el-radio-button label="2">执行一次</el-radio-button>
+                <el-radio-button label="3">放弃执行</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="状态">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{ dict.dictLabel }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" round @click="submitForm">确 定</el-button>
+        <el-button round @click="cancel">取 消</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 任务日志详细 -->
+    <el-dialog title="任务详细" :visible.sync="openView" width="700px" append-to-body>
+      <el-form ref="form" :model="form" label-width="120px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="任务编号:">{{ form.jobId }}</el-form-item>
+            <el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="任务分组:">{{ jobGroupFormat(form) }}</el-form-item>
+            <el-form-item label="创建时间:">{{ form.createTime }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="cron表达式:">{{ form.cronExpression }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="下次执行时间:">{{ parseTime(form.nextValidTime) }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="调用目标方法:">{{ form.invokeTarget }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="任务状态:">
+              <div v-if="form.status == 0">正常</div>
+              <div v-else-if="form.status == 1">失败</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="是否并发:">
+              <div v-if="form.concurrent == 0">允许</div>
+              <div v-else-if="form.concurrent == 1">禁止</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="执行策略:">
+              <div v-if="form.misfirePolicy == 0">默认策略</div>
+              <div v-else-if="form.misfirePolicy == 1">立即执行</div>
+              <div v-else-if="form.misfirePolicy == 2">执行一次</div>
+              <div v-else-if="form.misfirePolicy == 3">放弃执行</div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="openView = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from '@/network/api/job/job'
+
+export default {
+  name: 'Job',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 定时任务表格数据
+      jobList: [],
+      // 弹出层标题
+      title: '',
+      // 是否显示弹出层
+      open: false,
+      // 是否显示详细弹出层
+      openView: false,
+      // 任务组名字典
+      jobGroupOptions: [],
+      // 状态字典
+      statusOptions: [{ dictValue: '0', dictLabel: '正常' }, { dictValue: '1', dictLabel: '暂停' }],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jobName: undefined,
+        jobGroup: undefined,
+        status: undefined
+      },
+      // 表单参数
+      form: { },
+      self,
+      // 表单校验
+      rules: {
+        jobName: [
+          { required: true, message: '任务名称不能为空', trigger: 'blur' }
+        ],
+        invokeTarget: [
+          { required: true, message: '调用目标字符串不能为空', trigger: 'blur' }
+        ],
+        cronExpression: [
+          { required: true, message: 'cron执行表达式不能为空', trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  created() {
+    this.getList()
+    this.getDicts('sys_job_group').then(response => {
+      this.jobGroupOptions = response.data
+    })
+    this.getDicts('sys_job_status').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询定时任务列表 */
+    getList() {
+      this.loading = true
+      listJob(this.queryParams).then(response => {
+        this.jobList = response.rows
+        this.total = response.total
+        this.loading = false
+      })
+    },
+    // 任务组名字典翻译
+    jobGroupFormat(row, column) {
+      return this.selectDictLabel(this.jobGroupOptions, row.jobGroup)
+    },
+    // 状态字典翻译
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false
+      this.reset()
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+        jobId: undefined,
+        jobName: undefined,
+        jobGroup: undefined,
+        invokeTarget: undefined,
+        cronExpression: undefined,
+        misfirePolicy: 1,
+        concurrent: 1,
+        status: '0'
+      }
+      this.resetForm('form')
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.jobId)
+      this.single = selection.length !== 1
+      this.multiple = !selection.length
+    },
+    // 更多操作触发
+    handleCommand(command, row) {
+      switch (command) {
+        case 'handleRun':
+          this.handleRun(row)
+          break
+        case 'handleView':
+          this.handleView(row)
+          break
+        case 'handleJobLog':
+          this.handleJobLog(row)
+          break
+        default:
+          break
+      }
+    },
+    // 任务状态修改
+    handleStatusChange(row) {
+      const text = row.status === '0' ? '启用' : '停用'
+      this.$confirm('确认要"' + text + '""' + row.jobName + '"任务吗?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return changeJobStatus(row.jobId, row.status)
+      }).then(response => {
+        if (response.code !== null && response.code === 200) {
+          this.$message({
+            message: response.msg,
+            type: 'success'
+          })
+        } else {
+          this.$message.error(response.msg)
+        }
+      }).catch(function() {
+        this.getList()
+        // row.status = row.status === '0' ? '1' : '0'
+      })
+    },
+    /* 立即执行一次 */
+    handleRun(row) {
+      this.$confirm('确认要立即执行一次"' + row.jobName + '"任务吗?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return runJob(row.jobId, row.jobGroup)
+      }).then(response => {
+        if (response.code !== null && response.code === 200) {
+          this.$message({
+            message: response.msg,
+            type: 'success'
+          })
+        } else {
+          this.$message.error(response.msg)
+        }
+      }).catch(() => {})
+    },
+    /** 任务详细信息 */
+    handleView(row) {
+      getJob(row.jobId).then(response => {
+        this.form = response.data
+        this.openView = true
+      })
+    },
+    /** 任务日志列表查询 */
+    handleJobLog(row) {
+      const jobId = row.jobId || 0
+      this.$router.push({ path: '/job-log', query: { jobId: jobId }})
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset()
+      this.open = true
+      this.form.status = '1'
+      this.title = '添加任务'
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset()
+      const jobId = row.jobId || this.ids
+      getJob(jobId).then(response => {
+        this.form = response.data
+        this.open = true
+        this.title = '修改任务'
+      })
+    },
+    /** 提交按钮 */
+    submitForm: function() {
+      this.$refs['form'].validate(valid => {
+        if (valid) {
+          if (this.form.jobId !== undefined) {
+            updateJob(this.form).then(response => {
+              if (response.code !== null && response.code === 200) {
+                this.$message({
+                  message: response.msg,
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message.error(response.msg)
+              }
+            })
+          } else {
+            addJob(this.form).then(response => {
+              if (response.code !== null && response.code === 200) {
+                this.$message({
+                  message: response.msg,
+                  type: 'success'
+                })
+                this.open = false
+                this.getList()
+              } else {
+                this.$message.error(response.msg)
+              }
+            })
+          }
+        }
+      })
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const jobIds = row.jobId || this.ids
+      this.$confirm('是否确认删除定时任务编号为"' + jobIds + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delJob(jobIds)
+      }).then(response => {
+        if (response.code !== null && response.code === 200) {
+          this.$message({
+            message: response.msg,
+            type: 'success'
+          })
+          this.getList()
+        } else {
+          this.$message.error(response.msg)
+        }
+      }).catch(() => {})
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('schedule/job/export', {
+        ...this.queryParams
+      }, `job_${new Date().getTime()}.xlsx`)
+    }
+  }
+}
+</script>
+<style scoped>
+
+</style>

+ 343 - 0
src/views/job/log.vue

@@ -0,0 +1,343 @@
+<template>
+  <div class="app-container">
+    <!-- <el-form v-show="showSearch" ref="queryForm" :model="queryParams" :inline="true" label-width="68px">
+      <el-form-item label="任务名称" prop="jobName">
+        <el-input
+          v-model="queryParams.jobName"
+          placeholder="请输入任务名称"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="任务组名" prop="jobGroup">
+        <el-select
+          v-model="queryParams.jobGroup"
+          placeholder="请任务组名"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in jobGroupOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="执行状态" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="请选择执行状态"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="执行时间">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form> -->
+
+    <el-row :gutter="10" class="justify-left ">
+      <el-button
+        v-hasPermi="['monitor:job:remove']"
+        type="danger"
+        plain
+        icon="el-icon-delete"
+        size="mini"
+        :disabled="multiple"
+        @click="handleDelete"
+      >删除</el-button>
+      <!-- <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['monitor:job:remove']"
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+        >删除</el-button>
+      </el-col> -->
+      <el-button
+        v-hasPermi="['monitor:job:remove']"
+        type="danger"
+        plain
+        icon="el-icon-delete"
+        size="mini"
+        @click="handleClean"
+      >清空</el-button>
+      <!-- <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['monitor:job:remove']"
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+        >清空</el-button>
+      </el-col> -->
+      <!-- <el-col :span="1.5">
+        <el-button
+          v-hasPermi="['monitor:job:export']"
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+        >导出</el-button>
+      </el-col> -->
+      <el-button
+        type="warning"
+        plain
+        icon="el-icon-close"
+        size="mini"
+        @click="handleClose"
+      >关闭</el-button>
+      <!-- <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-close"
+          size="mini"
+          @click="handleClose"
+        >关闭</el-button>
+      </el-col> -->
+      <!-- <right-toolbar class="ml-5" :show-search.sync="showSearch" @queryTable="getList" /> -->
+    </el-row>
+
+    <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="日志编号" width="80" align="center" prop="jobLogId" />
+      <el-table-column label="任务名称" align="center" prop="jobName" :show-overflow-tooltip="true" />
+      <!-- <el-table-column label="任务组名" align="center" prop="jobGroup" :formatter="jobGroupFormat" :show-overflow-tooltip="true" /> -->
+      <el-table-column label="调用目标字符串" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+      <el-table-column label="日志信息" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
+      <el-table-column label="执行状态" align="center" prop="status" :formatter="statusFormat" />
+      <!-- <el-table-column label="异常信息" align="center" prop="exceptionInfo" :show-overflow-tooltip="true" /> -->
+
+      <el-table-column label="执行时间" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            v-hasPermi="['monitor:job:query']"
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row)"
+          >详细</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <paginations
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 调度日志详细 -->
+    <el-dialog title="调度日志详细" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="日志序号:">{{ form.jobLogId }}</el-form-item>
+            <el-form-item label="任务名称:">{{ form.jobName }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <!-- <el-form-item label="任务分组:">{{ form.jobGroup }}</el-form-item> -->
+            <el-form-item label="执行时间:">{{ form.createTime }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="调用方法:">{{ form.invokeTarget }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="日志信息:">{{ form.jobMessage }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="执行状态:">
+              <div v-if="form.status == 0">正常</div>
+              <div v-else-if="form.status == 1">失败</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item v-if="form.status == 1" label="异常信息:">{{ form.exceptionInfo }}</el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="open = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getJob } from '@/network/api/job/job'
+import { listJobLog, delJobLog, cleanJobLog } from '@/network/api/job/jobLog'
+
+export default {
+  name: 'JobLog',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 调度日志表格数据
+      jobLogList: [],
+      // 是否显示弹出层
+      open: false,
+      // 日期范围
+      dateRange: [],
+      // 表单参数
+      form: {},
+      // 执行状态字典
+      statusOptions: [{ dictValue: '0', dictLabel: '正常' }, { dictValue: '1', dictLabel: '暂停' }],
+      // 任务组名字典
+      jobGroupOptions: [],
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jobName: undefined,
+        jobGroup: undefined,
+        status: undefined
+      }
+    }
+  },
+  created() {
+    const jobId = this.$route.query.jobId
+    if (jobId !== undefined && jobId !== 0) {
+      getJob(jobId).then(response => {
+        this.queryParams.jobName = response.data.jobName
+        this.queryParams.jobGroup = response.data.jobGroup
+        this.getList()
+      })
+    } else {
+      this.getList()
+    }
+    // this.getDicts('sys_common_status').then(response => {
+    //   this.statusOptions = response.data
+    // })
+    this.getDicts('sys_job_group').then(response => {
+      this.jobGroupOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询调度日志列表 */
+    getList() {
+      this.loading = true
+      // this.addDateRange(this.queryParams, this.dateRange)
+      listJobLog(this.queryParams).then(response => {
+        this.jobLogList = response.rows
+        this.total = response.total
+        this.loading = false
+      }
+      )
+    },
+    // 执行状态字典翻译
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+    // 任务组名字典翻译
+    jobGroupFormat(row, column) {
+      return this.selectDictLabel(this.jobGroupOptions, row.jobGroup)
+    },
+    // 返回按钮
+    handleClose() {
+      this.$store.dispatch('tagsView/delView', this.$route)
+      this.$router.push({ path: '/taskScheduling' })
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.dateRange = []
+      this.resetForm('queryForm')
+      this.handleQuery()
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.jobLogId)
+      this.multiple = !selection.length
+    },
+    /** 详细按钮操作 */
+    handleView(row) {
+      this.open = true
+      this.form = row
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const jobLogIds = this.ids
+      this.$confirm('是否确认删除调度日志编号为"' + jobLogIds + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delJobLog(jobLogIds)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      })
+    },
+    /** 清空按钮操作 */
+    handleClean() {
+      this.$confirm('是否确认清空所有调度日志数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return cleanJobLog()
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('清空成功')
+      })
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('schedule/job/log/export', {
+        ...this.queryParams
+      }, `log_${new Date().getTime()}.xlsx`)
+    }
+  }
+}
+</script>

+ 342 - 0
src/views/operlog/index.vue

@@ -0,0 +1,342 @@
+<template>
+  <div class="app-container">
+    <el-form v-show="showSearch" ref="queryForm" class="search-form" :model="queryParams" :inline="true" label-width="68px">
+      <el-form-item label="" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="请输入系统模块"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="" prop="operName">
+        <el-input
+          v-model="queryParams.operName"
+          placeholder="请输入操作人员"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="" prop="businessType">
+        <el-select
+          v-model="queryParams.businessType"
+          placeholder="操作类型"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="操作状态"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="操作时间开始日期"
+          end-placeholder="操作时间结束日期"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">查询</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8" style="    display: flex;">
+
+      <el-button
+
+        type="danger"
+        plain
+        icon="el-icon-delete"
+        size="mini"
+        round
+        :disabled="multiple"
+        @click="handleDelete"
+      >删除</el-button>
+
+      <el-button
+
+        type="danger"
+        plain
+        round
+        icon="el-icon-delete"
+        size="mini"
+        @click="handleClean"
+      >清空</el-button>
+
+      <el-button
+        type="warning"
+        plain
+        round
+        icon="el-icon-download"
+        size="mini"
+        @click="handleExport"
+      >导出</el-button>
+
+      <right-toolbar class="ml-10" :show-search.sync="showSearch" @queryTable="getList" />
+    </el-row>
+
+    <el-table ref="tables" v-loading="loading" :data="list" :default-sort="defaultSort" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="日志编号" align="center" prop="operId" />
+      <el-table-column label="系统模块" align="center" prop="title" />
+      <el-table-column label="操作类型" align="center" prop="businessType" :formatter="typeFormat" />
+      <el-table-column label="请求方式" align="center" prop="requestMethod" />
+      <el-table-column label="操作人员" align="center" prop="operName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" width="100" />
+      <el-table-column label="主机" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
+      <el-table-column label="操作状态" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="操作日期" align="center" prop="operTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.operTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row,scope.index)"
+          >详细</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <paginations
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 操作日志详细 -->
+    <el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
+            <el-form-item
+              label="登录信息:"
+            >{{ form.operName }} / {{ form.operIp }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
+            <el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="操作方法:">{{ form.method }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="操作状态:">
+              <div v-if="form.status === 0">正常</div>
+              <div v-else-if="form.status === 1">失败</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item v-if="form.status === 1" label="异常信息:">{{ form.errorMsg }}</el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="open = false">关 闭</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list, delOperlog, cleanOperlog } from '@/network/api/system/operlog'
+
+export default {
+  name: 'Operlog',
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // 表格数据
+      list: [],
+      // 是否显示弹出层
+      open: false,
+      // 类型数据字典
+      typeOptions: [
+        // { dictLabel: '新增', dictValue: '1' },
+        // { dictLabel: '修改', dictValue: '2' },
+        // { dictLabel: '删除', dictValue: '3' },
+        // { dictLabel: '授权', dictValue: '4' },
+        // { dictLabel: '导出', dictValue: '5' },
+        // { dictLabel: '导入', dictValue: '6' },
+        // { dictLabel: '强退', dictValue: '7' },
+        // { dictLabel: '清空数据', dictValue: '9' }
+
+      ],
+      // 类型数据字典
+      statusOptions: [
+        // { dictLabel: '正常', dictValue: '0' },
+        // { dictLabel: '失败', dictValue: '1' }
+      ],
+      // 日期范围
+      dateRange: [],
+      // 默认排序
+      defaultSort: { prop: 'operTime', order: 'descending' },
+      // 表单参数
+      form: {},
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: undefined,
+        operName: undefined,
+        businessType: undefined,
+        operTimeQuery: undefined,
+        status: undefined
+      }
+    }
+  },
+  created() {
+    this.getList()
+    this.getDicts('sys_oper_type').then(response => {
+      this.typeOptions = response.data
+    })
+    this.getDicts('sys_common_status').then(response => {
+      this.statusOptions = response.data
+    })
+  },
+  methods: {
+    /** 查询登录日志 */
+    getList() {
+      if (this.dateRange.length === 2) {
+        var zreo = this.dateRange[0]
+        var one = this.dateRange[1]
+        this.queryParams.operTimeQuery = zreo + ',' + one
+      }
+      this.loading = true
+      list(this.queryParams).then(response => {
+        this.list = response.rows
+        this.total = response.total
+        this.loading = false
+      }
+      )
+    },
+    // 操作日志状态字典翻译
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status)
+    },
+    // 操作日志类型字典翻译
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.typeOptions, row.businessType)
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1
+      this.getList()
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+      this.queryParams.operTimeQuery = undefined
+      this.dateRange = []
+      this.resetForm('queryForm')
+      this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
+      this.handleQuery()
+    },
+    /** 多选框选中数据 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.operId)
+      this.multiple = !selection.length
+    },
+    /** 排序触发事件 */
+    handleSortChange(column, prop, order) {
+      this.queryParams.orderByColumn = column.prop
+      this.queryParams.isAsc = column.order
+      this.getList()
+    },
+    /** 详细按钮操作 */
+    handleView(row) {
+      this.open = true
+      this.form = row
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const operIds = row.operId || this.ids
+      this.$confirm('是否确认删除日志编号为"' + operIds + '"的数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return delOperlog(operIds)
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('删除成功')
+      }).catch(() => {})
+    },
+    /** 清空按钮操作 */
+    handleClean() {
+      this.$confirm('是否确认清空所有操作日志数据项?', '警告', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(function() {
+        return cleanOperlog()
+      }).then(() => {
+        this.getList()
+        this.msgSuccess('清空成功')
+      }).catch(() => {})
+    },
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('/api/system/operlog/export', {
+        ...this.queryParams
+      }, `operlog_${new Date().getTime()}.xlsx`)
+    }
+  }
+}
+</script>
+

+ 3 - 2
vue.config.js

@@ -15,13 +15,14 @@ module.exports = {
     },
     },
     disableHostCheck: true,
     disableHostCheck: true,
     proxy: {
     proxy: {
-      '/admin': {
+      '/api': {
         target: 'http://172.16.15.220:7002',
         target: 'http://172.16.15.220:7002',
         changeOrigin: true,
         changeOrigin: true,
         pathRewrite: {
         pathRewrite: {
-          '^/admin': '/admin'
+          '^/api': '/'
         }
         }
       }
       }
+
     }
     }
   },
   },
   css: {
   css: {