joway пре 2 година
родитељ
комит
d782759ad9

+ 0 - 5
package.json

@@ -106,11 +106,6 @@
       "git add"
     ]
   },
-  "husky": {
-    "hooks": {
-      "pre-commit": "lint-staged"
-    }
-  },
   "repository": {
     "type": "git",
     "url": "git+https://github.com/PanJiaChen/vue-element-admin.git"

+ 73 - 0
src/api/filter.js

@@ -0,0 +1,73 @@
+import request from '@/utils/request'
+
+// 过滤
+export function filterUser(query) {
+  return request({
+    url: '/v1/user/filter-user',
+    method: 'get',
+    data: query
+  })
+}
+
+// 删除角色
+export function deleteRole(id) {
+  return request({
+    url: '/v1/admin/role-delete/' + id,
+    method: 'get',
+    data: {}
+  })
+}
+
+// 批量删除角色
+export function batchDeleteRole(query) {
+  return request({
+    url: '/v1/admin/role-delete',
+    method: 'post',
+    data: query
+  })
+}
+
+// 列表
+export function adminRole(query) {
+  return request({
+    url: '/v1/admin/role',
+    method: 'get',
+    data: query,
+    params: query
+  })
+}
+
+// 编辑角色获取详情
+export function roleDetail(id) {
+  return request({
+    url: '/v1/admin/role-edit/' + id,
+    method: 'get',
+    data: {}
+  })
+}
+
+// 添加/编辑角色
+export function addOREditRole(path, query) {
+  return request({
+    url: '/v1/' + path,
+    method: 'post',
+    data: query
+  })
+}
+
+// 获取角色权限
+export function getRolePermission(id) {
+  return request({
+    url: '/v1/admin/role-permission/' + id,
+    method: 'get'
+  })
+}
+
+// 编辑角色权限
+export function editRolePermission(id, query) {
+  return request({
+    url: '/v1/admin/role-permission/' + id,
+    method: 'post',
+    data: query
+  })
+}

+ 620 - 0
src/components/FilterUser.vue

@@ -0,0 +1,620 @@
+<template>
+  <div class="filter-user">
+    <div class="filter-option">
+      <el-select
+        v-model="filterType"
+        class="filter-item"
+        :placeholder="$t('common.selectType')"
+        @change="handleFilterTypeChange"
+      >
+        <el-option v-for="(item,key) in allFilterTypes" :key="key" :label="item.name" :value="key" />
+      </el-select>
+      <el-select
+        v-model="filterSymbol"
+        class="filter-item"
+        :placeholder="$t('common.selectFunction')"
+      >
+        <el-option v-for="(item,key) in filterSymbols" :key="key" :label="item" :value="key" />
+      </el-select>
+      <template
+        v-if="filterType !== '' && allFilterTypes[filterType].hasOwnProperty('other') && allFilterTypes[filterType].other === 'date'"
+      >
+        <el-date-picker
+          v-model="filterValue"
+          class="filter-item"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetime"
+          :placeholder="$t('common.selectDate')"
+        />
+      </template>
+      <template
+        v-else-if="filterType !== '' && allFilterTypes[filterType].hasOwnProperty('other') && allFilterTypes[filterType].other === 'month'"
+      >
+        <el-date-picker
+          v-model="filterValue"
+          class="filter-item"
+          value-format="yyyyMM"
+          type="month"
+          :placeholder="$t('common.selectMonth')"
+        />
+      </template>
+      <template
+        v-else-if="filterType !== '' && allFilterTypes[filterType].hasOwnProperty('other') && allFilterTypes[filterType].other === 'area'"
+      >
+        <el-cascader
+          v-model="filterAreaValue"
+          class="filter-item"
+          :options="regionData"
+          :props="{ checkStrictly: true }"
+        />
+      </template>
+      <template
+        v-else-if="filterType !== '' && allFilterTypes[filterType].hasOwnProperty('other') && allFilterTypes[filterType].other === 'select'"
+      >
+        <el-select
+          v-model="filterValue"
+          class="filter-item"
+          :placeholder="`请选择${allFilterTypes[filterType].name}`"
+        >
+          <el-option
+            v-for="(item,key) in allFilterTypes[filterType].selectData"
+            :key="key"
+            :label="item.name"
+            :value="item.id"
+          />
+        </el-select>
+      </template>
+      <template
+        v-else-if="filterType !== '' && allFilterTypes[filterType].hasOwnProperty('other') && filterCustomType.hasOwnProperty(allFilterTypes[filterType].other)"
+      >
+        <el-select v-model="filterValue" class="filter-item" :placeholder="`${filterCustomType[allFilterTypes[filterType].other].placeholder}`">
+          <el-option v-for="(item,key) in filterCustomType[allFilterTypes[filterType].other].values" :key="key" :label="item[filterCustomType[allFilterTypes[filterType].other].labelField]" :value="item[filterCustomType[allFilterTypes[filterType].other].valueField]" />
+        </el-select>
+      </template>
+      <template v-else>
+        <el-input v-model="filterValue" class="filter-item filter-value" :placeholder="$t('common.pleaseInputContent')" />
+      </template>
+      <el-select
+        v-model="filterRelation"
+        class="filter-item filter-relation"
+        :placeholder="$t('common.relation')"
+      >
+        <el-option v-for="(item,key) in filterRelations" :key="key" :label="item" :value="key" />
+      </el-select>
+      <el-button class="filter-item" icon="el-icon-plus" @click="handleOptionPlus" />
+      <el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilterUser">{{ filterBtnName }}</el-button>
+      <el-button class="filter-item" type="" @click="handleFilterClear">{{ $t('common.reset') }}</el-button>
+      <el-button class="down-button" type="text"><i class="el-icon-arrow-down" /></el-button>
+    </div>
+    <div v-show="filterSelected.length > 0" class="filter-selected">
+      <el-tag
+        v-for="(item,key) in filterSelected"
+        :key="key"
+        class="selected-tag"
+        closable
+        @close="handleCloseTag(key)"
+      >{{ item.filterTypeName }} {{ item.filterSymbolName }} {{ item.filterName }}
+      </el-tag>
+    </div>
+    <el-dialog :title="$t('filter.memberSelect')" :visible.sync="filterUserDialogShow" width="80%">
+      <el-table
+        v-loading="loading"
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column type="selection" width="55" />
+        <el-table-column :label="$t('filter.memberNumber')">
+          <template slot-scope="scope">
+            {{ scope.row.USER_NAME }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('filter.name')">
+          <template slot-scope="scope">
+            {{ scope.row.REAL_NAME }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('filter.idNumber')" width="180">
+          <template slot-scope="scope">
+            {{ scope.row.ID_CARD }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('filter.phoneNumber')">
+          <template slot-scope="scope">
+            {{ scope.row.MOBILE }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('filter.memberLevel')">
+          <template slot-scope="scope">
+            {{ scope.row.DEC_LV ? filterCustomType.decLevel.values[scope.row.DEC_LV]['LEVEL_NAME'] : '' }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('filter.level')">
+          <template slot-scope="scope">
+            {{ scope.row.EMP_LV ? filterCustomType.empLevel.values[scope.row.EMP_LV]['LEVEL_NAME'] : '' }}
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button type="primary" size="small" :disabled="multipleSelectionUserId == undefined || multipleSelectionUserId.length <= 0?true:false" @click="handleSelectValue(false)">{{ $t('filter.confirmSelect') }}</el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { filterUser } from '@/api/filter'
+import baseInfo from '@/utils/baseInfo'
+import store from '@/utils/vuexStore'
+import Pagination from './Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'FilterUser',
+  components: { Pagination },
+  props: {
+    filterTypes: {
+      type: Object,
+      default() {
+        return {
+          'USER_NAME': { isUserTable: true, name: this.$t('filter.memberNumber') },
+          'REAL_NAME': { isUserTable: true, name: this.$t('filter.memberName') },
+          'ID_CARD': { isUserTable: true, name: this.$t('filter.ID') },
+          'MOBILE': { isUserTable: true, name: this.$t('filter.phoneNumber') },
+          'CREATED_AT': { isUserTable: true, name: this.$t('filter.addAt'), other: 'date' }
+        }
+      }
+    },
+    filterBtnName: {
+      type: String,
+      default() {
+        return this.$t('filter.memberSelect')
+      }
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      filterUserDialogShow: false,
+      tableData: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      // filterCustomType: {
+      //   decLevel: {
+      //     placeholder: this.$t('filter.pleaseSelectDecLevel'),
+      //     labelField: 'LEVEL_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.decLevels()
+      //   },
+      //   empLevel: {
+      //     placeholder: this.$t('filter.pleaseSelectEmpLevel'),
+      //     labelField: 'LEVEL_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.empLevels()
+      //   },
+      //   decRole: {
+      //     placeholder: '请选择报单中心级别',
+      //     labelField: 'ROLE_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.decRoles()
+      //   },
+      //   subCompany: {
+      //     placeholder: '请选择分公司',
+      //     labelField: 'COM_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.subCompanies()
+      //   },
+      //   status: {
+      //     placeholder: '请选择会员状态',
+      //     labelField: 'label',
+      //     valueField: 'value',
+      //     values: baseInfo.allStatus()
+      //   },
+      //   dealTypes: {
+      //     placeholder: '请选择交易类型',
+      //     labelField: 'TYPE_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.dealTypes()
+      //   },
+      //   systems: {
+      //     placeholder: '请选择体系',
+      //     labelField: 'SYSTEM_NAME',
+      //     valueField: 'ID',
+      //     values: baseInfo.systems()
+      //   },
+      //   sex: {
+      //     placeholder: '请选择性别',
+      //     labelField: 'label',
+      //     valueField: 'value',
+      //     values: {
+      //       '男': { label: '男', value: '男' },
+      //       '女': { label: '女', value: '女' }
+      //     }
+      //   },
+      //   yesOrNo: {
+      //     placeholder: '请选择是否',
+      //     labelField: 'label',
+      //     valueField: 'value',
+      //     values: {
+      //       1: { label: '是', value: 1 },
+      //       0: { label: '否', value: 0 }
+      //     }
+      //   },
+      //   banks: {
+      //     placeholder: '请选择开户行',
+      //     labelField: 'BANK_NAME',
+      //     valueField: 'BANK_CODE',
+      //     values: baseInfo.allOpenBank()
+      //   },
+      //   nations: {
+      //     placeholder: '请选择民族',
+      //     labelField: 'name',
+      //     valueField: 'id',
+      //     values: baseInfo.allNation()
+      //   },
+      //   location: {
+      //     placeholder: '请选择市场',
+      //     labelField: 'label',
+      //     valueField: 'value',
+      //     values: {
+      //       1: { label: '一市场', value: 1 },
+      //       2: { label: '二市场', value: 2 },
+      //       3: { label: '三市场', value: 3 },
+      //       4: { label: '四市场', value: 4 },
+      //       5: { label: '五市场', value: 5 }
+      //     }
+      //   }
+      // },
+      filterModel: {
+        userId: ''
+      },
+      allFilterTypes: this.filterTypes,
+      filterType: '',
+      filterSymbol: '',
+      // filterSymbols: {
+      //   '=': this.$t('filter.eq'),
+      //   'like': this.$t('filter.like'),
+      //   '<>': this.$t('filter.noeq'),
+      //   'notLike': this.$t('filter.nolike'),
+      //   '>': this.$t('filter.moreThan'),
+      //   '>=': this.$t('filter.moreThanEq'),
+      //   '<': this.$t('filter.less'),
+      //   '<=': this.$t('filter.lessThan')
+      // },
+      filterRelation: 'and',
+      // filterRelations: {
+      //   'and': this.$t('filter.and'),
+      //   'or': this.$t('filter.or')
+      // },
+      filterValue: '',
+      filterName: '',
+      filterSelected: [],
+      selectData: [],
+      multipleSelection: [],
+      multipleSelectionUserId: [],
+      regionData: store.state.regionInfo.regionData,
+      filterAreaValue: [],
+      filterRequest: {}
+    }
+  },
+  computed: {
+    filterCustomType() {
+      return {
+        decLevel: {
+          placeholder: this.$t('filter.pleaseSelectDecLevel'),
+          labelField: 'LEVEL_NAME',
+          valueField: 'ID',
+          values: baseInfo.decLevels()
+        },
+        empLevel: {
+          placeholder: this.$t('filter.pleaseSelectEmpLevel'),
+          labelField: 'LEVEL_NAME',
+          valueField: 'ID',
+          values: baseInfo.empLevels()
+        },
+        decRole: {
+          placeholder: '请选择报单中心级别',
+          labelField: 'ROLE_NAME',
+          valueField: 'ID',
+          values: baseInfo.decRoles()
+        },
+        subCompany: {
+          placeholder: '请选择分公司',
+          labelField: 'COM_NAME',
+          valueField: 'ID',
+          values: baseInfo.subCompanies()
+        },
+        status: {
+          placeholder: '请选择会员状态',
+          labelField: 'label',
+          valueField: 'value',
+          values: baseInfo.allStatus()
+        },
+        dealTypes: {
+          placeholder: '请选择交易类型',
+          labelField: 'TYPE_NAME',
+          valueField: 'ID',
+          values: baseInfo.dealTypes()
+        },
+        systems: {
+          placeholder: '请选择体系',
+          labelField: 'SYSTEM_NAME',
+          valueField: 'ID',
+          values: baseInfo.systems()
+        },
+        sex: {
+          placeholder: '请选择性别',
+          labelField: 'label',
+          valueField: 'value',
+          values: {
+            '男': { label: '男', value: '男' },
+            '女': { label: '女', value: '女' }
+          }
+        },
+        yesOrNo: {
+          placeholder: '请选择是否',
+          labelField: 'label',
+          valueField: 'value',
+          values: {
+            1: { label: '是', value: 1 },
+            0: { label: '否', value: 0 }
+          }
+        },
+        banks: {
+          placeholder: '请选择开户行',
+          labelField: 'BANK_NAME',
+          valueField: 'BANK_CODE',
+          values: baseInfo.allOpenBank()
+        },
+        nations: {
+          placeholder: '请选择民族',
+          labelField: 'name',
+          valueField: 'id',
+          values: baseInfo.allNation()
+        },
+        location: {
+          placeholder: '请选择市场',
+          labelField: 'label',
+          valueField: 'value',
+          values: {
+            1: { label: '一市场', value: 1 },
+            2: { label: '二市场', value: 2 },
+            3: { label: '三市场', value: 3 },
+            4: { label: '四市场', value: 4 },
+            5: { label: '五市场', value: 5 }
+          }
+        }
+      }
+    },
+    filterSymbols() {
+      return {
+        '=': this.$t('filter.eq'),
+        'like': this.$t('filter.like'),
+        '<>': this.$t('filter.noeq'),
+        'notLike': this.$t('filter.nolike'),
+        '>': this.$t('filter.moreThan'),
+        '>=': this.$t('filter.moreThanEq'),
+        '<': this.$t('filter.less'),
+        '<=': this.$t('filter.lessThan')
+      }
+    },
+    filterRelations() {
+      return {
+        'and': this.$t('filter.and'),
+        'or': this.$t('filter.or')
+      }
+    }
+
+  },
+  watch: {
+    filterTypes(newVal) {
+      this.allFilterTypes = this.filterTypes
+    }
+  },
+  methods: {
+    handleFilterTypeChange() {
+      this.filterValue = ''
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+      this.multipleSelectionUserId = []
+      for (const i in this.multipleSelection) {
+        this.multipleSelectionUserId.push(this.multipleSelection[i].ID)
+      }
+    },
+    handleCurrentChange(page) {
+      this.getData(this.filterRequest, page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.filterRequest, this.currentPage, pageSize)
+    },
+    remoteMethod(query) {
+      if (query !== '') {
+        this.loading = true
+        filterUser({ kw: query }).then(response => {
+          this.selectData = response
+          this.loading = false
+        }).catch(err => {
+          this.loading = false
+        })
+      }
+    },
+    handleOptionPlus() {
+      if (this.filterType === '' || this.filterSymbol === '' || (this.filterValue === '' && this.filterAreaValue === [])) {
+        this.$message({
+          message: this.$t('filter.selectContentNotice'),
+          type: 'warning'
+        })
+        return false
+      }
+      let valueName = this.filterValue
+      if (this.filterType !== '' && this.allFilterTypes[this.filterType].hasOwnProperty('other')) {
+        // 获取下拉筛选时的选中项
+        if (this.allFilterTypes[this.filterType].other === 'select') {
+          let nameObj = []
+          const _this = this
+          if (!Array.isArray(this.allFilterTypes[this.filterType].selectData)) {
+            nameObj[0] = this.allFilterTypes[this.filterType].selectData[_this.filterValue]
+          } else {
+            nameObj = (this.allFilterTypes[this.filterType].selectData).filter(function(item, index, array) {
+              return item.id === _this.filterValue
+            })
+          }
+          valueName = nameObj[0] ? nameObj[0].name : null
+        } else if (this.allFilterTypes[this.filterType].other === 'area') {
+          if (this.filterSymbol !== '=') {
+            this.$message({
+              message: this.$t('filter.areaSelectNotice'),
+              type: 'warning'
+            })
+            return false
+          }
+          this.filterValue = this.filterAreaValue.join(',')
+          valueName = ''
+          for (const i in this.regionData) {
+            if (this.regionData[i].value === this.filterAreaValue[0]) {
+              valueName += this.regionData[i].label + ','
+              for (const j in this.regionData[i].children) {
+                if (this.regionData[i].children[j].value === this.filterAreaValue[1]) {
+                  valueName += this.regionData[i].children[j].label + ','
+                  for (const h in this.regionData[i].children[j].children) {
+                    if (this.regionData[i].children[j].children[h].value === this.filterAreaValue[2]) {
+                      valueName += this.regionData[i].children[j].children[h].label
+                      break
+                    }
+                  }
+                  break
+                }
+              }
+              break
+            }
+          }
+        } else if (this.filterCustomType.hasOwnProperty(this.allFilterTypes[this.filterType].other)) {
+          const allCustomData = this.filterCustomType[this.allFilterTypes[this.filterType].other].values
+          const customField = this.filterCustomType[this.allFilterTypes[this.filterType].other].labelField
+          valueName = allCustomData[this.filterValue][customField]
+        }
+      }
+      // 如果是筛选会员编号,则把会员编号转成小写
+      // if(this.filterType === 'USER_NAME'){
+      //   this.filterValue = this.filterValue.toLowerCase()
+      // }
+
+      this.filterSelected.push({
+        filterType: this.filterType,
+        filterTypeName: this.allFilterTypes[this.filterType].name,
+        filterSymbol: this.filterSymbol,
+        filterSymbolName: this.filterSymbols[this.filterSymbol],
+        filterValue: this.filterValue,
+        filterRelation: this.filterRelation,
+        filterRelationName: this.filterRelations[this.filterRelation],
+        filterName: valueName,
+        filterOther: this.filterType !== '' && this.allFilterTypes[this.filterType].hasOwnProperty('other') ? this.allFilterTypes[this.filterType].other : null,
+        isUserTable: this.allFilterTypes[this.filterType].isUserTable
+      })
+    },
+    handleCloseTag(tag) {
+      this.filterSelected.splice(tag, 1)
+    },
+    handleFilterUser() {
+      console.log('===>>>', this.filterSelected.length, '<<===')
+      if (this.filterSelected.length > 0) {
+        this.loading = true
+        this.filterRequest = {}
+        for (const i in this.filterSelected) {
+          if (this.filterSelected[i].isUserTable) {
+            let reqFilterValue = `${this.filterSelected[i].filterSymbol},${this.filterSelected[i].filterValue}`
+            if (this.filterSelected[i].hasOwnProperty('filterOther')) {
+              reqFilterValue += `,${this.filterSelected[i].filterOther}`
+            }
+            const filterType = this.filterSelected[i].filterType
+            if (this.filterRequest[filterType]) {
+              this.$set(this.filterRequest, filterType, (this.filterRequest[filterType] + '|' + reqFilterValue))
+            } else {
+              this.$set(this.filterRequest, filterType, reqFilterValue)
+            }
+          }
+        }
+        if (Object.keys(this.filterRequest).length === 0) {
+          this.handleSelectValue(true)
+        } else {
+          this.getData(this.filterRequest, this.currentPage)
+        }
+      }
+    },
+    getData(request, page = null, pageSize = null) {
+      request.page = page
+      request.pageSize = pageSize
+
+      filterUser(this.listQuery).then(response => {
+        this.filterUserDialogShow = true
+      })
+    },
+    handleSelectValue(isAll = false) {
+      const otherFilterTypes = []
+      for (const i in this.filterSelected) {
+        if (!this.filterSelected[i].isUserTable) {
+          otherFilterTypes.push(this.filterSelected[i])
+        }
+      }
+      let userIds = this.multipleSelectionUserId
+      if (isAll) {
+        userIds = 'all'
+      }
+      this.$emit('select-value', {
+        userIds: userIds,
+        otherFilterTypes: otherFilterTypes
+      })
+      this.filterUserDialogShow = false
+    },
+    handleFilterClear() {
+      Object.assign(this.$data, this.$options.data())
+      this.allFilterTypes = this.filterTypes
+      // 清空地址栏
+      filterHelper.clearFilterOption(this)
+      this.$emit('select-value', { userIds: 'all', otherFilterTypes: [] })
+    }
+  }
+}
+</script>
+
+  <style scoped>
+    .filter-option:after {
+      content: '';
+      clear: both;
+      display: table;
+    }
+
+    .filter-item {
+      float: left;
+      margin-left: 10px;
+    }
+
+    .filter-value {
+      width: 200px;
+    }
+
+    .filter-relation {
+      width: 100px;
+      display: none;
+    }
+
+    .down-button {
+      float: right;
+    }
+
+    .filter-selected {
+      clear: both;
+      margin: 10px;
+      padding: 5px;
+      border: 1px solid #ebeef5;
+    }
+
+    .selected-tag {
+      margin-left: 10px;
+    }
+  </style>

+ 61 - 68
src/components/Pagination/index.vue

@@ -1,101 +1,94 @@
 <template>
-  <div :class="{'hidden':hidden}" class="pagination-container">
+  <div style="float: right;">
     <el-pagination
-      :background="background"
-      :current-page.sync="currentPage"
-      :page-size.sync="pageSize"
-      :layout="layout"
       :page-sizes="pageSizes"
-      :total="total"
-      v-bind="$attrs"
-      @size-change="handleSizeChange"
-      @current-change="handleCurrentChange"
+      :page-size="pageSize"
+      :background="background"
+      :layout="pageLayout"
+      :total="pageTotal"
+      @size-change="sizeChange"
+      @current-change="currentChange"
     />
   </div>
 </template>
 
 <script>
-import { scrollTo } from '@/utils/scroll-to'
-
 export default {
   name: 'Pagination',
   props: {
     total: {
-      required: true,
+      default: 0,
       type: Number
     },
-    page: {
-      type: Number,
-      default: 1
-    },
-    limit: {
-      type: Number,
-      default: 20
+    page_sizes: {
+      default: function() {
+        return [1, 2, 5, 10, 20]
+      },
+      type: Array
     },
-    pageSizes: {
-      type: Array,
-      default() {
-        return [10, 20, 30, 50]
-      }
+    page_size: {
+      default: 20,
+      type: Number
     },
     layout: {
-      type: String,
-      default: 'total, sizes, prev, pager, next, jumper'
-    },
-    background: {
-      type: Boolean,
-      default: true
+      default: 'total, sizes, prev, pager, next, jumper',
+      type: String
     },
-    autoScroll: {
-      type: Boolean,
-      default: true
+    page: {
+      default: 1,
+      type: Number
     },
-    hidden: {
-      type: Boolean,
-      default: false
+    background: {
+      default: true,
+      type: Boolean
     }
   },
-  computed: {
-    currentPage: {
-      get() {
-        return this.page
-      },
-      set(val) {
-        this.$emit('update:page', val)
-      }
+  data() {
+    return {
+      pageTotal: 1,
+      pageSizes: null,
+      pageSize: 20,
+      pageLayout: null,
+      colSpan: 18
+    }
+  },
+  watch: {
+    total() {
+      this.pageTotal = this.total
     },
-    pageSize: {
-      get() {
-        return this.limit
-      },
-      set(val) {
-        this.$emit('update:limit', val)
-      }
+    page_sizes() {
+      this.pageSizes = this.page_sizes
+    },
+    page_size() {
+      this.pageSize = this.page_size
+    },
+    layout() {
+      this.pageLayout = this.layout
+    },
+    span() {
+      this.colSpan = this.span
     }
   },
+  created() {
+    this.pageTotal = this.total
+    this.pageSizes = this.page_sizes
+    this.pageSize = this.page_size
+    this.pageLayout = this.layout
+    this.colSpan = this.span
+  },
+  mounted() {
+  },
   methods: {
-    handleSizeChange(val) {
-      this.$emit('pagination', { page: this.currentPage, limit: val })
-      if (this.autoScroll) {
-        scrollTo(0, 800)
-      }
+    currentChange(currentPage) {
+      this.$emit('current-change', currentPage)
     },
-    handleCurrentChange(val) {
-      this.$emit('pagination', { page: val, limit: this.pageSize })
-      if (this.autoScroll) {
-        scrollTo(0, 800)
-      }
+    sizeChange(size) {
+      this.$emit('size-change', size)
     }
   }
 }
 </script>
 
 <style scoped>
-.pagination-container {
-  background: #fff;
-  padding: 32px 16px;
-}
-.pagination-container.hidden {
-  display: none;
-}
+
 </style>

+ 51 - 1
src/lang/en.js

@@ -219,7 +219,44 @@ export default {
     canNotBeBlank: ' cannot be blank',
     require: 'is required',
     createdAt: '创建时间',
-    updatedAt: '更新时间'
+    updatedAt: '更新时间',
+    actionThisData: '操作该数据',
+    selectType: '筛选类型',
+    selectFunction: '筛选方式',
+    selectDate: '选择日期',
+    selectMonth: '选择月份',
+    pleaseInputContent: '请输入内容',
+    relation: '关系',
+    reset: '重置',
+    desc: '描述'
+  },
+
+  filter: {
+    memberSelect: '会员筛选',
+    memberNumber: '会员编号',
+    name: '姓名',
+    idNumber: '证件号码',
+    phoneNumber: '手机号码',
+    memberLevel: '会员级别',
+    level: '级别',
+    confirmSelect: '确认筛选',
+    memberName: '会员姓名',
+    ID: '身份证',
+    addAt: '加入时间',
+    pleaseSelectDecLevel: '请选择报单级别',
+    pleaseSelectEmpLevel: '请选择级别',
+    eq: '等于',
+    like: '包含',
+    noeq: '不等于',
+    nolike: '不包含',
+    moreThan: '大于',
+    moreThanEq: '大于等于',
+    less: '小于',
+    lessThan: '小于等于',
+    and: '并且',
+    or: '或者',
+    selectContentNotice: '请填写完整筛选内容',
+    areaSelectNotice: '地区仅限于"等于"的筛选方式'
   },
 
   menu: {
@@ -313,5 +350,18 @@ export default {
   // 财务
   financial: {
     serviceCharge: '服务费(%)'
+  },
+
+  // 管理员管理
+  Administrator: {
+    role: '角色',
+    remark: '备注',
+    creatUser: '创建人',
+    creatAt: '创建时间',
+    updateUser: '修改人',
+    updateAt: '修改时间',
+    addRole: '添加角色',
+    selectData: '所选数据',
+    roleName: '角色名称'
   }
 }

+ 53 - 1
src/lang/zh.js

@@ -104,6 +104,7 @@ export default {
     github: 'Github 地址'
   },
   permission: {
+    permission: '权限',
     addRole: '新增角色',
     editPermission: '编辑权限',
     roles: '你的权限',
@@ -192,6 +193,7 @@ export default {
   },
 
   common: {
+    screen: '筛选',
     save: '保存',
     modify: '修改',
     submit: '提交',
@@ -219,7 +221,44 @@ export default {
     canNotBeBlank: '不能为空',
     require: '必须填写',
     createdAt: '创建时间',
-    updatedAt: '更新时间'
+    updatedAt: '更新时间',
+    actionThisData: '操作该数据',
+    selectType: '筛选类型',
+    selectFunction: '筛选方式',
+    selectDate: '选择日期',
+    selectMonth: '选择月份',
+    pleaseInputContent: '请输入内容',
+    relation: '关系',
+    reset: '重置',
+    desc: '描述'
+  },
+
+  filter: {
+    memberSelect: '会员筛选',
+    memberNumber: '会员编号',
+    name: '姓名',
+    idNumber: '证件号码',
+    phoneNumber: '手机号码',
+    memberLevel: '会员级别',
+    level: '级别',
+    confirmSelect: '确认筛选',
+    memberName: '会员姓名',
+    ID: '身份证',
+    addAt: '加入时间',
+    pleaseSelectDecLevel: '请选择报单级别',
+    pleaseSelectEmpLevel: '请选择级别',
+    eq: '等于',
+    like: '包含',
+    noeq: '不等于',
+    nolike: '不包含',
+    moreThan: '大于',
+    moreThanEq: '大于等于',
+    less: '小于',
+    lessThan: '小于等于',
+    and: '并且',
+    or: '或者',
+    selectContentNotice: '请填写完整筛选内容',
+    areaSelectNotice: '地区仅限于"等于"的筛选方式'
   },
 
   // 菜单
@@ -314,6 +353,19 @@ export default {
   // 财务
   financial: {
     serviceCharge: '服务费(%)'
+  },
+
+  // 管理员管理
+  Administrator: {
+    role: '角色',
+    remark: '备注',
+    creatUser: '创建人',
+    creatAt: '创建时间',
+    updateUser: '修改人',
+    updateAt: '修改时间',
+    addRole: '添加角色',
+    selectData: '所选数据',
+    roleName: '角色名称'
   }
 
 }

+ 1 - 1
src/layout/index.vue

@@ -5,7 +5,7 @@
     <div :class="{hasTagsView:needTagsView}" class="main-container">
       <div :class="{'fixed-header':fixedHeader}">
         <navbar />
-        <tags-view v-if="needTagsView" />
+        <!-- <tags-view v-if="needTagsView" /> -->
       </div>
       <app-main />
       <right-panel v-if="showSettings">

+ 1 - 0
src/main.js

@@ -8,6 +8,7 @@ import Element from 'element-ui'
 import './styles/element-variables.scss'
 
 import '@/styles/index.scss' // global css
+import '@/styles/style.scss' // 项目全局样式
 
 import App from './App'
 import store from './store'

+ 25 - 0
src/router/index.js

@@ -48,6 +48,31 @@ export const constantRoutes = [
       }
     ]
   },
+  {
+    path: '/admin',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: '/admin/role',
+        component: () => import('@/views/admin/role') // 管理员角色列表
+      },
+      {
+        path: '/admin/role-add',
+        component: () => import('@/views/admin/role-add') // 添加角色
+      },
+      {
+        path: '/admin/role-edit/:id',
+        name: 'admin_role-edit',
+        component: () => import('@/views/admin/role-add') // 编辑角色
+      },
+      {
+        path: '/admin/role-permission/:id',
+        name: 'admin_role-permission',
+        component: () => import('@/views/admin/role-permission') // 角色权限
+      }
+    ]
+  },
   {
     path: '/login',
     component: () => import('@/views/login/index'),

+ 595 - 0
src/styles/style.scss

@@ -0,0 +1,595 @@
+html, body, #app {
+    font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
+    height: 100%;
+}
+.app-main {
+    padding: 20px;
+    background-color: #f0f2f5;
+}
+
+/* 滚动条 */
+::-webkit-scrollbar-thumb:horizontal { /*水平滚动条的样式*/
+    background-color: rgba(64,158,255,.3);
+}
+::-webkit-scrollbar-track-piece {
+    background-color: #fff; /*滚动条的背景颜色*/
+    -webkit-border-radius: 0; /*滚动条的圆角宽度*/
+}
+::-webkit-scrollbar {
+    width: 10px; /*滚动条的宽度*/
+    height: 6px; /*滚动条的高度*/
+    background:#f4f4f5;
+}
+::-webkit-scrollbar-thumb:vertical { /*垂直滚动条的样式*/
+    background-color: rgba(64,158,255,.3);
+    outline: 2px solid #fff;
+    outline-offset: -2px;
+    border: 2px solid #fff;
+}
+::-webkit-scrollbar-thumb:hover { /*滚动条的hover样式*/
+    background-color: #66b1ff;
+}
+
+a {
+    text-decoration: none;
+}
+
+.display-none {
+    display: none !important;
+}
+
+.loading-icon {
+
+}
+
+.el-container {
+    height: 100%;
+}
+
+.el-header {
+    background-color: #4f5467;
+    color: #fff;
+    line-height: 60px;
+    position: absolute;
+    top: 0;
+    height: 60px;
+    width: 100%;
+}
+
+.el-header a, .el-header button {
+    color: #fff;
+}
+
+.el-header h4{display: inline;}
+
+.el-header .el-breadcrumb{float: right;line-height: 60px;}
+.el-header .el-breadcrumb .el-breadcrumb__item .el-breadcrumb__inner{color: #f0f0f0;}
+.el-header .el-breadcrumb .el-breadcrumb__item:last-child .el-breadcrumb__inner{color: #409EFF;}
+
+.el-main {
+    width: 100%;
+}
+
+.el-main .white-box{margin-bottom: 0;box-shadow: 0 1px 20px rgba(0, 0, 0, .08)}
+
+.el-menu--collapse {
+    width: 59px;
+}
+
+.al-left {
+    float: left;
+}
+
+.img-circle {
+    border-radius: 50%;
+}
+
+.layout-menu-left {
+    width: 100%;
+    margin: 0;
+    padding: 0;
+    list-style-type: none;
+}
+
+.layout-menu-left li {
+    list-style-type: none;
+    display: inline;
+    margin: 10px;
+}
+
+.top-message {
+    position: relative;
+}
+
+.top-message-card {
+    width: 200px;
+    height: 300px;
+    position: absolute;
+    top: 41px;
+    left: 0px;
+    z-index: 1;
+    background: #fff;
+    border: 1px solid rgba(120, 130, 140, .21);
+
+}
+
+.el-aside {
+    background: #fff;
+    width: 100%;
+    z-index: 1;
+    display: none;
+    margin-top: 60px;
+}
+
+.el-aside::-webkit-scrollbar {
+    width: 0;
+}
+
+.el-aside, .el-main {
+    /*overflow: visible !important;*/
+}
+
+.el-aside.show-menu {
+    display: block;
+}
+
+.el-container {
+    display: block;
+}
+
+.layout-menu-left li.scale-menu {
+    display: none;
+}
+
+.layout-menu-left li.mobile-menu {
+    display: inline;
+}
+
+.el-menu {
+    border: none;
+}
+
+.el-menu .site-title h1 {
+    text-align: center;
+}
+
+.el-menu li {
+    font-size: 14px;
+}
+
+.el-menu li i {
+    font-size: 14px;
+}
+
+.el-menu li span {
+    margin-left: 0px;
+}
+
+.el-menu-item .el-submenu__title {
+    color: #54667a;
+    font-weight: 100;
+}
+
+.el-menu-item.is-active {
+    border-left: 3px solid #f75b36;
+    font-weight: bold;
+    color: #3e4d6c;
+}
+
+.el-menu-item.is-active i {
+    color: #f75b36;
+    font-weight: normal;
+}
+
+.el-menu .user-profile {
+    padding: 15px 0;
+    position: relative;
+    text-align: center;
+}
+
+.el-menu .user-profile .profile-avatar {
+    width: 50px;
+    height: 50px;
+    display: block;
+    margin: 0 auto 10px;
+    text-align: left;
+}
+
+.el-menu .user-profile .profile-username {
+    color: #54667a;
+    font-size: 14px;
+}
+
+.el-menu .user-profile .divider {
+    height: 1px;
+    margin: 9px 0;
+    overflow: hidden;
+    background-color: #e5e5e5;
+}
+
+.el-menu .user-profile .profile-card {
+    background: #fff;
+    border: 1px solid rgba(120, 130, 140, .21);
+    position: absolute;
+    top: 100px;
+    left: 10px;
+    width: 180px;
+    z-index: 2;
+    margin: 0;
+    padding: 0;
+    list-style-type: none;
+    text-align: left;
+    overflow: hidden;
+
+}
+
+.el-menu .user-profile .profile-card li {
+    list-style-type: none;
+    line-height: 38px;
+    padding: 0 15px;
+}
+
+.el-menu .user-profile .profile-card a {
+    color: #54667a;
+}
+
+.breadcrumb-box {
+    background: #fff;
+    padding: 15px 15px 10px;
+    margin-bottom: 5px;
+    margin-top: 60px;
+    overflow: auto;
+}
+
+.breadcrumb-box.show-menu {
+    margin-top: 5px;
+}
+
+.breadcrumb-box h4 {
+    width: 20%;
+    float: left;
+    color: rgba(0, 0, 0, .5);
+    font-weight: 500;
+    margin: 6px 0;
+}
+
+.breadcrumb-box .breadcrumb-content {
+    width: 80%;
+    float: right;
+}
+
+.breadcrumb-box .breadcrumb-content .el-breadcrumb {
+    float: right;
+    line-height: 28px;
+}
+
+.el-breadcrumb .el-breadcrumb__item .el-breadcrumb__inner {
+    font-size: 14px;
+    font-weight: normal;
+}
+
+.el-breadcrumb .el-breadcrumb__item:last-child .el-breadcrumb__inner {
+    font-weight: normal;
+    color: #f75b36;
+    cursor: text;
+}
+
+.waves-btn {
+    width: 100%;
+}
+
+.white-box {
+    background: #fff;
+    padding: 25px;
+    // margin-bottom: 15px;
+    overflow: auto;
+}
+
+.white-box .white-box-title {
+    margin: 0 0 12px;
+    font-weight: 500;
+    text-transform: uppercase;
+    font-size: 16px;
+    line-height: 30px;
+}
+
+.white-box .white-box-footer {
+    background: #fff;
+    padding-top: 15px;
+    box-sizing: border-box;
+    overflow: auto;
+}
+
+.text-center {
+    text-align: center;
+}
+
+.text-white {
+    color: #fff
+}
+
+.text-danger {
+    color: #f75b36
+}
+
+.text-muted {
+    color: #8d9ea7
+}
+
+.text-warning {
+    color: #f8c255
+}
+
+.text-success {
+    color: #00c292
+}
+
+.text-info {
+    color: #008efa
+}
+
+.text-inverse {
+    color: #3e4d6c
+}
+
+.text-blue {
+    color: #02bec9
+}
+
+.text-primary, .text-purple {
+    color: #2c5ca9
+}
+
+.text-megna {
+    color: #00b5c2
+}
+
+.text-dark {
+    color: #686868 !important
+}
+
+.box-bg-primary {
+    background-color: #2c5ca9 !important
+}
+
+.box-bg-success {
+    background-color: #00c292 !important
+}
+
+.box-bg-info {
+    background-color: #008efa !important
+}
+
+.box-bg-warning {
+    background-color: #f8c255 !important
+}
+
+.box-bg-danger {
+    background-color: #f75b36 !important
+}
+
+.box-bg-theme {
+    background-color: #ff6849 !important
+}
+
+.box-bg-theme-dark {
+    background-color: #4f5467 !important
+}
+
+.box-bg-gray {
+    background-color: #e6eaef !important
+}
+
+.box-bg-inverse {
+    background-color: #3e4d6c !important
+}
+
+.box-bg-extlgt {
+    background-color: #f7fafc !important
+}
+
+.box-bg-purple {
+    background-color: #2c5ca9 !important
+}
+
+.box-bg-dark {
+    background-color: #3e4d6c !important
+}
+
+.box-bg-white {
+    background-color: #fff !important
+}
+
+.box-bg-megna {
+    background-color: #00b5c2 !important
+}
+
+.el-pagination {
+    float: right;
+}
+
+.el-pagination .el-pagination__total {
+    display: none !important;
+}
+
+.el-pagination .el-pagination__sizes {
+    display: none !important;
+}
+
+.el-pagination .el-pager {
+    display: none !important;
+}
+
+.el-pagination .el-pagination__jump {
+    display: none !important;
+}
+
+.el-pagination .btn-prev {
+    background-color: #409EFF !important;
+    color: #fff !important;
+}
+
+.el-pagination .btn-next {
+    background-color: #409EFF !important;
+    color: #fff !important;
+    margin-left: 5px;
+}
+
+.panel {
+    border-radius: 3px;
+    margin-bottom: 15px;
+    border-color: rgba(120, 130, 140, .21);
+    box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
+}
+
+.panel .panel-heading {
+    color: #3e4d6c;
+    background-color: #fff;
+    border-bottom: 1px solid rgba(120, 130, 140, .21);
+    border-radius: 3px;
+    font-weight: 500;
+    text-transform: uppercase;
+    padding: 20px 25px;
+}
+
+.panel > .panel-heading {
+    border-color: #ddd;
+}
+
+.panel-wrapper {
+    display: block;
+}
+
+.panel .panel-body {
+    padding: 25px;
+    color: #3e4d6c;
+    background-color: #fff;
+}
+
+.panel .panel-footer {
+    background: #fff;
+    color: #3e4d6c;
+    border-top: 1px solid rgba(120, 130, 140, .21);
+    border-radius: 3px;
+    padding: 15px 25px;
+    box-sizing: border-box;
+    overflow: auto;
+}
+
+.admin-role-box .el-checkbox + .el-checkbox {
+    margin-left: 0 !important;
+}
+
+.admin-role-box .el-checkbox {
+    margin-right: 15px;
+}
+
+.number-font {
+    font-family: RubikLight;
+}
+
+@media (min-width: 768px) {
+    .el-aside {
+        width: 220px;
+        box-shadow: 1px 0 20px rgba(0, 0, 0, .08);
+        display: block;
+        margin-top: 0;
+    }
+
+    .el-container {
+        display: flex;
+    }
+
+    .el-header {
+        position: static;
+        top: auto;
+        height: 60px;
+        width: auto;
+    }
+
+    .layout-menu-left {
+        /* width: 500px; */
+		width: 400px;
+    }
+
+    .breadcrumb-box {
+        margin-top: 0;
+        overflow: inherit;
+    }
+
+    .layout-menu-left li.mobile-menu {
+        display: none;
+    }
+
+    .layout-menu-left li.scale-menu {
+        display: inline;
+    }
+
+    .el-pagination .el-pagination__total {
+        display: inline-block !important;
+    }
+
+    .el-pagination .el-pagination__sizes {
+        display: inline-block !important;
+    }
+
+    .el-pagination .el-pager {
+        display: inline-block !important;
+    }
+
+    .el-pagination .el-pagination__jump {
+        display: inline-block !important;
+    }
+
+    .el-pagination .btn-prev {
+        background: none !important;
+        color: #c0c4cc !important;
+    }
+
+    .el-pagination .btn-next {
+        background: none !important;
+        color: #c0c4cc !important;
+        margin-left: 0;
+    }
+
+    .content-wrapper .el-aside {
+        width: 60px;
+    }
+
+    .content-wrapper .el-menu {
+        width: 59px;
+    }
+
+    .content-wrapper .el-menu .user-profile .profile-avatar {
+        width: 40px;
+        height: 40px;
+    }
+
+    .content-wrapper .el-menu .user-profile .profile-username {
+        display: none;
+    }
+
+    .content-wrapper .el-menu-item.is-active {
+        overflow: hidden;
+    }
+
+}
+
+/*细节修改*/
+.filter-box{margin-bottom: 20px;}
+.filter-box .filter-item,.filter-user .el-input-group{vertical-align: middle}
+.el-table th{background: #f5f5f5;border-top: 2px solid #ddd;border-bottom: 1px solid #ddd;font-weight: normal;color: #999;user-select: auto!important;}
+.no-border{border-right-color:transparent;border-bottom-color:transparent;border-top-color:transparent;border-radius: 0;border-left-width: 2px;}
+td .cell .no-border{font-size: 14px;color: #666; font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
+}
+.el-tree-node>.el-tree-node__children{overflow: visible;}
+.el-table__footer .cell{white-space: pre-line;}
+.addr {
+    display: inline-block;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+}
+.el-dropdown-menu__item{white-space: nowrap}
+.form-page{width: 650px;}
+.form-page .el-form-item > .el-form-item__content > .el-input,.form-page .el-form-item > .el-form-item__content > .el-cascader,.form-page .el-form-item > .el-form-item__content > .el-select,.form-page .el-form-item > .el-form-item__content > .el-textarea,.form-page .el-form-item > .el-form-item__content > .el-slider{width: 400px;}
+.form-dialog .el-form-item > .el-form-item__content > .el-input,.form-dialog .el-form-item > .el-form-item__content > .el-cascader,.form-dialog .el-form-item > .el-form-item__content > .el-select,.form-dialog .el-form-item > .el-form-item__content > .el-textarea,.form-dialog .el-form-item > .el-form-item__content > .el-slider{width: 350px;}

+ 47 - 0
src/utils/filterHelper.js

@@ -0,0 +1,47 @@
+import tool from './tool'
+
+const filterHelper = {
+
+  /**
+   * 筛选
+   * @param thisObj
+   * @param filterData
+   */
+  handleFilterUser(thisObj, filterData) {
+    thisObj.filterModel = {}
+    if (filterData.userIds !== 'all') {
+      thisObj.$set(thisObj.filterModel, 'userIds', `in,${filterData.userIds.join()}`)
+    }
+    for (const i in filterData.otherFilterTypes) {
+      let filterValue = `${filterData.otherFilterTypes[i].filterSymbol},${filterData.otherFilterTypes[i].filterValue}`
+      if (filterData.otherFilterTypes[i].hasOwnProperty('filterOther')) {
+        filterValue += `,${filterData.otherFilterTypes[i].filterOther}`
+      }
+      const filterType = filterData.otherFilterTypes[i].filterType
+      if (thisObj.filterModel[filterType]) {
+        thisObj.$set(thisObj.filterModel, filterType, (thisObj.filterModel[filterType] + '|' + filterValue))
+      } else {
+        thisObj.$set(thisObj.filterModel, filterType, filterValue)
+      }
+    }
+    // this.filterModel放在地址栏 供刷新时可以保留筛选结果
+    tool.insertUrlParam('filter', thisObj.filterModel)
+
+    thisObj.getData()
+  },
+  /**
+   * 清空筛选条件
+   * @param thisObj
+   */
+  clearFilterOption(thisObj) {
+    thisObj.filterModel = {}
+    tool.insertUrlParam('filter', '')
+    window.location.href = window.location.href.replace(/(\?|&)filter=/, '')
+    if (thisObj.$refs.filterUser) {
+      thisObj.$refs.filterUser.handleFilterClear()
+    }
+  }
+
+}
+
+export default filterHelper

+ 30 - 47
src/utils/permission.js

@@ -1,52 +1,35 @@
-import store from '@/store'
-import usersInfo from '@/utils/usersInfo'
-import baseInfo from '@/utils/baseInfo'
-import tool from '@/utils/tool'
+import baseInfo from './baseInfo'
+import userInfo from './usersInfo'
+import tool from './tool'
 
-/**
- * @param {Array} value
- * @returns {Boolean}
- * @example see @/views/permission/directive.vue
- */
-export function checkPermission(value) {
-  if (value && value instanceof Array && value.length > 0) {
-    const roles = store.getters && store.getters.roles
-    const permissionRoles = value
+const permission = {
 
-    const hasPermission = roles.some(role => {
-      return permissionRoles.includes(role)
-    })
-    return hasPermission
-  } else {
-    console.error(`need roles! Like v-permission="['admin','editor']"`)
-    return false
+  /**
+   * 获取权限
+   * @returns {*}
+   */
+  getPermission() {
+    // 自己的管理组
+    const role = userInfo.baseData().roleId
+    if (role === baseInfo.superAdminRoleId()) {
+      return 'all'
+    } else {
+      // 全部的管理员权限
+      const allAdminRoles = baseInfo.adminRoles()
+      // 自己的权限
+      return allAdminRoles[role].PERMISSION
+    }
+  },
+  /**
+   * 是否拥有权限该路由的权限
+   * @param route
+   * @returns {boolean}
+   */
+  hasPermission(route) {
+    const permissions = this.getPermission()
+    if (permissions === 'all') return true
+    return tool.isInArray(permissions, route)
   }
 }
 
-/**
- * 获取权限
- * @returns {string|*}
- */
-export function getPermission() {
-  // 自己的管理组
-  const role = usersInfo.baseData().roleId
-  if (role === baseInfo.superAdminRoleId()) {
-    return 'all'
-  } else {
-    // 全部的管理员权限
-    const allAdminRoles = baseInfo.adminRoles()
-    // 自己的权限
-    return allAdminRoles[role].PERMISSION
-  }
-}
-
-/**
- * 是否拥有权限该路由的权限
- * @param route
- * @returns {boolean}
- */
-export function hasPermission(route) {
-  const permissions = this.getPermission()
-  if (permissions === 'all') return true
-  return tool.isInArray(permissions, route)
-}
+export default permission

+ 32 - 0
src/utils/tool.js

@@ -144,6 +144,15 @@ const tool = {
       }
     }
   },
+  /**
+   * 是否空对象
+   * @param obj
+   * @returns {boolean}
+   */
+  isEmptyObject(obj) {
+    const objArr = Object.keys(obj)
+    return objArr.length === 0
+  },
   isInArray(arr, value) {
     for (const i in arr) {
       if (value === arr[i]) {
@@ -235,6 +244,29 @@ const tool = {
 
   getEmpLv(id) {
     // return id.length > 0 ? getBaseInfo().empLevels : 'No Rank';
+  },
+  /**
+   * 向地址来看
+   * @param paramName
+   * @param value
+   */
+  insertUrlParam(paramName, value) {
+    if (typeof value === 'object') {
+      if (tool.isEmptyObject(value)) {
+        return
+      }
+      value = JSON.stringify(value)
+    }
+    if (window.location.href.indexOf(paramName) === -1) {
+      if (window.location.href.indexOf('?') !== -1) {
+        window.location.href += ('&' + paramName + '=' + value)
+      } else {
+        window.location.href += ('?' + paramName + '=' + value)
+      }
+    } else {
+      const searchStr = new RegExp('(\\?|&)(' + paramName + '=)([^&]*)(&|$)')
+      window.location.href = window.location.href.replace(searchStr, '$1$2' + value + '$4')
+    }
   }
 }
 

+ 41 - 0
src/utils/vuexStore.js

@@ -0,0 +1,41 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+
+Vue.use(Vuex)
+
+const moduleSocket = {
+  state: {
+    socketObj: null,
+    onMessageCallback: null
+  }
+}
+const moduleBaseInfo = {
+  state: {
+    decLevels: null,
+    empLevels: null,
+    adminRoles: null,
+    menu: null,
+    daysDiff: null
+  }
+}
+
+const moduleRegionInfo = {
+  state: {
+    provinceAndCityData: [],
+    regionData: [],
+    provinceAndCityDataPlus: [],
+    regionDataPlus: [],
+    CodeToText: {
+      '': null
+    },
+    TextToCode: {}
+  }
+}
+
+export default new Vuex.Store({
+  modules: {
+    socket: moduleSocket,
+    baseInfo: moduleBaseInfo,
+    regionInfo: moduleRegionInfo
+  }
+})

+ 78 - 0
src/views/admin/role-add.vue

@@ -0,0 +1,78 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <el-form ref="form" :model="form" label-width="250px" class="form-page">
+        <el-form-item :label="$t('Administrator.roleName')">
+          <el-input v-model="form.roleName" />
+        </el-form-item>
+        <el-form-item :label="$t('common.desc')">
+          <el-input v-model="form.remark" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" :loading="submitButtonStat" @click="onSubmit">{{ $t('common.save') }}</el-button>
+        </el-form-item>
+      </el-form>
+    </div>
+  </div>
+</template>
+
+<script>
+import { roleDetail, addOREditRole } from '@/api/filter'
+export default {
+  name: 'RoleAdd',
+  data() {
+    return {
+      form: {
+        roleName: null,
+        remark: null
+      },
+      loading: false,
+      submitButtonStat: false
+    }
+  },
+  mounted() {
+    if (this.$route.name === 'admin_role-edit') {
+      roleDetail(this.$route.params.id).then(response => {
+        this.form.roleName = response.data.ROLE_NAME
+        this.form.remark = response.data.REMARK
+        this.loading = false
+      }).catch(err => {
+        console.log('err---------' + err)
+      })
+    }
+  },
+  methods: {
+    onSubmit() {
+      this.submitButtonStat = true
+      let path = 'admin/role-add'
+      if (this.$route.name === 'admin_role-edit') {
+        path = 'admin/role-edit/' + this.$route.params.id
+      }
+      addOREditRole(path, this.form).then(response => {
+        this.submitButtonStat = false
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+        this.$router.go(-1)
+      }).catch(err => {
+        console.log('err---------' + err)
+      })
+      // network.postData(path, this.form).then(response => {
+      //   this.submitButtonStat = false
+      //   this.$message({
+      //     message: response,
+      //     type: 'success'
+      //   })
+      //   this.$router.go(-1)
+      // }).catch(() => {
+      //   this.submitButtonStat = false
+      // })
+    }
+  }
+}
+</script>
+
+  <style scoped>
+
+  </style>

+ 137 - 0
src/views/admin/role-permission.vue

@@ -0,0 +1,137 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box admin-role-box">
+      <el-table :data="tableData" border style="width: 100%">
+        <el-table-column label="模块" width="180">
+          <template slot-scope="scope">
+            <el-checkbox
+              v-model="mainCheck[scope.row.id]"
+              :indeterminate="isIndeterminate[scope.row.id]"
+              @change="handleCheckAllChange(scope.row.id, scope.row.childPermission)"
+            >
+              {{ scope.row.mainPermission.name }}
+            </el-checkbox>
+          </template>
+        </el-table-column>
+        <el-table-column label="权限">
+          <template slot-scope="scope">
+            <el-checkbox-group
+              v-model="checkedValue"
+              class="checkgroup"
+              @change="handlePermissionChange(scope.row.id, scope.row.childPermission)"
+            >
+              <el-checkbox v-for="item in scope.row.childPermission" :key="item.name" :label="item.path">
+                {{ item.name }}
+              </el-checkbox>
+            </el-checkbox-group>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div style="margin-top: 20px">
+        <el-button type="primary" :loading="submitButtonStat" style="float: right;" @click="onSubmit">Submit<!-- 提交 --></el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import tool from '@/utils/tool'
+import { getRolePermission, editRolePermission } from '@/api/filter'
+
+export default {
+  name: 'RolePermission',
+  data() {
+    return {
+      tableData: null,
+      checkedValue: [],
+      mainCheck: {},
+      isIndeterminate: {},
+      loading: true,
+      submitButtonStat: false
+    }
+  },
+  created() {
+
+  },
+  mounted() {
+    getRolePermission(this.$route.params.id).then(response => {
+      this.tableData = response.data
+      this.checkedValue = []
+      for (const i of response.data) {
+        this.mainCheck[i] = false
+        for (const j of i.childPermission) {
+          if (j.isChecked) {
+            this.checkedValue.push(j.path)
+          }
+        }
+        this.initCheckValue(i.id, i.childPermission)
+      }
+      this.loading = false
+    }).catch(err => {
+      console.log('err---------' + err)
+    })
+  },
+  methods: {
+    handleCheckAllChange(id, child) {
+      // this.mainCheck[id] = !this.mainCheck[id];
+      if (this.mainCheck[id]) {
+        this.$set(this.isIndeterminate, id, false)
+        for (const i in child) {
+          tool.removeFromArr(this.checkedValue, child[i].path)
+          this.checkedValue.push(child[i].path)
+        }
+      } else {
+        this.$set(this.isIndeterminate, id, false)
+        for (const i in child) {
+          tool.removeFromArr(this.checkedValue, child[i].path)
+        }
+      }
+    },
+    handlePermissionChange(id, child) {
+      this.initCheckValue(id, child)
+    },
+    onSubmit() {
+      this.submitButtonStat = true
+      editRolePermission(this.$route.params.id, {
+        permission: this.checkedValue
+      }).then(response => {
+        this.submitButtonStat = false
+        this.$message({ message: response.data, type: 'success' })
+      }).catch(err => {
+        this.submitButtonStat = false
+        console.log('err---------' + err)
+      })
+    },
+    initCheckValue(id, child) {
+      let flag = true
+      for (const i in child) {
+        if (this.checkedValue.find(item => child[i].path === item) === undefined) {
+          flag = false
+        }
+      }
+      if (flag) {
+        this.$set(this.isIndeterminate, id, false)
+        this.$set(this.mainCheck, id, true)
+      } else {
+        this.$set(this.isIndeterminate, id, true)
+        this.$set(this.mainCheck, id, false)
+        let mainFlag = false
+        for (const i in this.checkedValue) {
+          if (child.find(item => this.checkedValue[i] === item.path) !== undefined) {
+            mainFlag = true
+          }
+        }
+        if (!mainFlag) {
+          this.$set(this.isIndeterminate, id, false)
+          this.$set(this.mainCheck, id, false)
+        }
+      }
+    }
+  }
+}
+</script>
+
+  <style scoped>
+
+  </style>

+ 247 - 0
src/views/admin/role.vue

@@ -0,0 +1,247 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user
+          :filter-types.sync="filterTypes"
+          :filter-btn-name="$t('common.screen')"
+          @select-value="handleFilterUser"
+        />
+      </div>
+      <el-table :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()" @selection-change="handleSelectionChange">
+        <el-table-column type="selection" width="55" />
+        <el-table-column prop="ROLE_NAME" :label="$t('Administrator.role')">
+          <template slot-scope="scope">
+            <el-tag type="warning" size="small" class="no-border">{{ scope.row.ROLE_NAME }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="REMARK" :label="$t('Administrator.remark')" />
+        <el-table-column :label="$t('Administrator.creatUser')">
+          <template slot-scope="scope">
+            {{ scope.row.CREATE_ADMIN_NAME }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('Administrator.creatAt')">
+          <template slot-scope="scope">
+            {{ tool.formatDate(scope.row.CREATED_AT) }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('Administrator.updateUser')">
+          <template slot-scope="scope">
+            {{ scope.row.UPDATE_ADMIN_NAME }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('Administrator.updateAt')">
+          <template slot-scope="scope">
+            {{ tool.formatDate(scope.row.UPDATED_AT) }}
+          </template>
+        </el-table-column>
+        <el-table-column fixed="right" :label="$t('table.actions')" width="180">
+          <template slot-scope="scope">
+            <el-dropdown v-if="scope.row.DONT_DEL==='0'&&(permission.hasPermission(`admin/role-permission`)||permission.hasPermission(`admin/role-edit`)||permission.hasPermission(`admin/role-delete`))" size="small" trigger="click" @command="handleRow" @click.stop="">
+              <el-button type="primary" size="small">
+                {{ $t('common.actionThisData') }}<i class="el-icon-arrow-down el-icon--right" />
+              </el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item v-if="permission.hasPermission(`admin/role-permission`)" :command="`permission|${scope.row.ID}`">{{ $t('permission.permission') }}</el-dropdown-item>
+                <!--                <el-dropdown-item :command="`column|${scope.row.ID}`" v-if="permission.hasPermission(`admin/role-column`)">列表字段权限</el-dropdown-item>-->
+                <el-dropdown-item v-if="permission.hasPermission(`admin/role-edit`)" :command="`edit|${scope.row.ID}`">{{ $t('table.edit') }}</el-dropdown-item>
+                <el-dropdown-item v-if="permission.hasPermission(`admin/role-delete`)" :command="`delete|${scope.row.ID}`">{{ $t('table.delete') }}</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-dropdown v-if="permission.hasPermission(`admin/role-delete`)" size="small" trigger="click" @command="muliDelHandle">
+          <el-button type="primary" size="small">
+            {{ $t('Administrator.selectData') }}<i class="el-icon-arrow-down el-icon--right" />
+          </el-button>
+          <el-dropdown-menu slot="dropdown">
+            <el-dropdown-item command="delete">{{ $t('table.delete') }}</el-dropdown-item>
+          </el-dropdown-menu>
+        </el-dropdown>
+        <el-button v-if="permission.hasPermission(`admin/role-add`)" type="primary" size="small" icon="el-icon-plus" @click="onAdd">{{ $t('Administrator.addRole') }}</el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { deleteRole, adminRole, batchDeleteRole } from '@/api/filter'
+import tool from '@/utils/tool'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '../../utils/filterHelper'
+
+export default {
+  name: 'Role',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      filterData: null,
+      filterTypes: {
+        'ROLE_NAME': { isUserTable: false, name: this.$t('Administrator.role') },
+        'REMARK': { isUserTable: false, name: this.$t('Administrator.remark') },
+        'CREATE_ADMIN_NAME': { isUserTable: false, name: this.$t('Administrator.creatUser') },
+        'CREATED_AT': { isUserTable: false, name: this.$t('Administrator.creatAt'), other: 'date' },
+        'UPDATE_ADMIN_NAME': { isUserTable: false, name: this.$t('Administrator.updateUser') },
+        'UPDATED_AT': { isUserTable: false, name: this.$t('Administrator.updateAt'), other: 'date' }
+      },
+      filterModel: {}
+    }
+  },
+  created() {
+
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleRow(command) {
+      const re = command.split('|')
+      this.handleCommand(re[0], re[1])
+    },
+    handleCommand(command, id) {
+      if (command === 'edit') {
+        this.$router.push({ path: `/admin/role-edit/${id}` })
+      } else if (command === 'permission') {
+        this.$router.push({ path: `/admin/role-permission/${id}` })
+      } else if (command === 'column') {
+        this.$router.push({ path: `/admin/role-column/${id}` })
+      } else if (command === 'delete') {
+        this.delHandle(this, id)
+      }
+    },
+    onAdd() {
+      this.$router.push({ path: `/admin/role-add` })
+    },
+    delHandle(obj, id) {
+      obj.$confirm(this.$t('common.deleteTips'), this.$t('common.hint'), {
+        confirmButtonText: this.$t('common.confirm'),
+        cancelButtonText: this.$t('common.cancel'),
+        type: 'warning'
+      }).then(() => {
+        deleteRole(id).then(response => {
+          this.$message({
+            message: response.data,
+            type: 'success'
+          })
+          this.getData()
+        }).catch(err => {
+          console.log('err---------' + err)
+        })
+
+        // network.getData(`admin/role-delete/${id}`).then(response => {
+        //   this.$message({
+        //     message: response,
+        //     type: 'success'
+        //   })
+        //   this.getData()
+        // })
+      })
+    },
+    muliDelHandle(command) {
+      if (command === 'delete') {
+        this.$confirm(this.$t('common.deleteTips'), this.$t('common.hint'), {
+          confirmButtonText: this.$t('common.confirm'),
+          cancelButtonText: this.$t('common.cancel'),
+          type: 'warning'
+        }).then(() => {
+          const selectedIds = []
+          for (const val of this.multipleSelection) {
+            selectedIds.push(val.ID)
+          }
+          batchDeleteRole({
+            selected: selectedIds
+          }).then(response => {
+            this.$message({
+              message: response.data,
+              type: 'success'
+            })
+            this.getData()
+          }).catch(err => {
+            console.log('err---------' + err)
+          })
+          //   network.postData(`admin/role-delete`, {
+          //     selected: selectedIds
+          //   }).then(response => {
+          //     this.$message({
+          //       message: response,
+          //       type: 'success'
+          //     })
+          //     this.getData()
+          //   })
+        })
+      }
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    handleFilter() {
+      this.getData()
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      const vueObj = this
+      const paramsData = Object.assign({
+        page: (page === null || page == undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize == undefined) ? vueObj.pageSize : pageSize
+      }, filterData)
+      adminRole(paramsData).then(response => {
+        vueObj.tableData = response.data.list
+        vueObj.currentPage = page
+        vueObj.totalPages = parseInt(response.data.totalPages)
+        vueObj.totalCount = parseInt(response.data.totalCount)
+        vueObj.pageSize = pageSize
+        this.loading = false
+      }).catch(err => {
+        console.log('err=============' + err)
+        this.loading = false
+      })
+      //   network.getPageData(this, 'admin/role', page, pageSize, filterData, function (response) {
+      //     vueObj.allData = response
+      //   })
+    }
+  }
+}
+</script>
+
+<style>
+.el-table th > .cell {
+  padding-left: 14px !important;
+  padding-right: 14px !important;
+}
+
+.el-table__fixed-right-patch {
+  width: 0px !important;
+}
+.pagination-container {
+  float: right;
+  padding: 0px 0px !important;
+  margin: 0 0;
+}
+.white-box-footer .el-dropdown {
+  margin-right: 10px;
+}
+</style>

+ 8 - 7
vue.config.js

@@ -27,7 +27,8 @@ module.exports = {
   publicPath: process.env.NODE_ENV === 'production' ? './' : '/',
   outputDir: 'dist',
   assetsDir: 'static',
-  lintOnSave: process.env.NODE_ENV === 'development',
+  // lintOnSave: process.env.NODE_ENV === 'development',
+  lintOnSave: false,
   productionSourceMap: false,
   devServer: {
     port: port,
@@ -37,15 +38,15 @@ module.exports = {
       errors: true
     },
     proxy: {
-      [process.env.VUE_APP_BASE_API]:{
-        target:"http://192.168.31.234:81",
-        changeOrigin:true,
-        pathRewrite:{
-          ["^" + process.env.VUE_APP_BASE_API] : ""
+      [process.env.VUE_APP_BASE_API]: {
+        target: 'http://192.168.31.234:81',
+        changeOrigin: true,
+        pathRewrite: {
+          ['^' + process.env.VUE_APP_BASE_API]: ''
         }
       }
     }
-    /*before: require('./mock/mock-server.js')*/
+    /* before: require('./mock/mock-server.js')*/
   },
   configureWebpack: {
     // provide the app's title in webpack's name field, so that