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

+ 2 - 0
.gitignore

@@ -21,3 +21,5 @@ selenium-debug.log
 
 package-lock.json
 yarn.lock
+
+.env.development

+ 143 - 0
src/api/bonus.js

@@ -0,0 +1,143 @@
+import request from '@/utils/request'
+
+export function fetchGetUserStatus() {
+  return request({
+    url: '/v1/user/status-audit-get-statuses',
+    method: 'get'
+  })
+}
+
+export function fetchBalanceList(query) {
+  return request({
+    url: '/v1/bonus/balance-list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchBalanceExport(query) {
+  return request({
+    url: '/v1/bonus/balance-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchOtherPeriodBonusFilterTypes(query) {
+  return request({
+    url: '/v1/bonus/other-period-bonus-filter-types',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchOtherPeriodBonus(query) {
+  return request({
+    url: '/v1/bonus/other-period-bonus',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchOtherPeriodBonusExport(query) {
+  return request({
+    url: '/v1/bonus/other-period-bonus-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchFlowBonus(query) {
+  return request({
+    url: '/v1/bonus/flow-bonus',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchFlowBonusExport(query) {
+  return request({
+    url: '/v1/bonus/flow-bonus-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchUserPerf(query) {
+  return request({
+    url: '/v1/bonus/user-perf',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchUserPerfExport(query) {
+  return request({
+    url: '/v1/bonus/user-perf-export',
+    method: 'get',
+    params: query
+  })
+}
+export function fetchPerfOrder(query) {
+  return request({
+    url: '/v1/bonus/perf-order',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfOrderExport(query) {
+  return request({
+    url: '/v1/bonus/perf-order-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfPeriodList(query) {
+  return request({
+    url: '/v1/bonus/perf-period-list',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfPeriodListExport(query) {
+  return request({
+    url: '/v1/bonus/perf-period-list-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfMonth(query) {
+  return request({
+    url: '/v1/bonus/perf-month',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfMonthExport(query) {
+  return request({
+    url: '/v1/bonus/perf-month-export',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfAdjustment(query) {
+  return request({
+    url: '/v1/bonus/perf-adjustment',
+    method: 'get',
+    params: query
+  })
+}
+
+export function fetchPerfAdjustmentPost(data) {
+  return request({
+    url: '/v1/bonus/perf-adjustment',
+    method: 'post',
+    data
+  })
+}

+ 9 - 0
src/api/file.js

@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+export function fetchExport(query) {
+  return request({
+    url: '/v1/file/export',
+    method: 'get',
+    params: query
+  })
+}

+ 13 - 0
src/lang/en.js

@@ -103,6 +103,19 @@ export default {
     hide: 'Hide',
     unhide: 'Unhide'
   },
+  file: {
+    exportName: 'Export Name',
+    route: 'Route',
+    download: 'Download',
+    operationAdministrator: 'Operation Administrator',
+    exportProgress: 'Export Progress',
+    exportStart: 'Export Start',
+    exportComplete: 'Export Complete',
+    createTime: 'Create time',
+    exportStartTime: 'Export Start Time',
+    exportEndTime: 'Export End Time',
+    creationTime: 'Creation Time'
+  },
   documentation: {
     documentation: 'Documentation',
     github: 'Github Repository'

+ 13 - 0
src/lang/zh.js

@@ -103,6 +103,19 @@ export default {
     hide: '展示',
     unhide: '不展示'
   },
+  file: {
+    exportName: '导出名称',
+    route: '路径',
+    download: '下载',
+    operationAdministrator: '操作管理员',
+    exportProgress: '导出进度',
+    exportStart: '导出开始',
+    exportComplete: '导出完成',
+    createTime: '创建时间',
+    exportStartTime: '导出开始时间',
+    exportEndTime: '导出结束时间',
+    creationTime: '创建时间'
+  },
   documentation: {
     documentation: '文档',
     github: 'Github 地址'

+ 70 - 0
src/router/index.js

@@ -270,6 +270,76 @@ export const asyncRoutes = [
       }
     ]
   },
+  {
+    path: '/file',
+    component: Layout,
+    redirect: '/file/export',
+    hidden: true,
+    children: [
+      {
+        path: 'export',
+        component: () => import('@/views/file/export'),
+        name: 'export',
+        meta: { title: 'export', noCache: true }
+      }
+    ]
+  },
+  {
+    path: '/bonus',
+    component: Layout,
+    redirect: '/bonus/balance-list',
+    hidden: true,
+    children: [
+      {
+        path: 'balance-list',
+        component: () => import('@/views/bonus/balance-list'),
+        name: 'balance-list',
+        meta: { title: 'balance-list', noCache: true }
+      },
+      {
+        path: 'other-period-bonus',
+        component: () => import('@/views/bonus/other-period-bonus'),
+        name: 'other-period-bonus',
+        meta: { title: 'other-period-bonus', noCache: true }
+      },
+      {
+        path: 'flow-bonus',
+        component: () => import('@/views/bonus/flow-bonus'),
+        name: 'flow-bonus',
+        meta: { title: 'flow-bonus', noCache: true }
+      },
+      {
+        path: 'user-perf',
+        component: () => import('@/views/bonus/user-perf'),
+        name: 'user-perf',
+        meta: { title: 'user-perf', noCache: true }
+      },
+      {
+        path: 'perf-order',
+        component: () => import('@/views/bonus/perf-order'),
+        name: 'perf-order',
+        meta: { title: 'perf-order', noCache: true }
+      },
+      {
+        path: 'perf-period-list',
+        component: () => import('@/views/bonus/perf-period-list'),
+        name: 'perf-period-list',
+        meta: { title: 'perf-period-list', noCache: true }
+      },
+      {
+        path: 'perf-month',
+        component: () => import('@/views/bonus/perf-month'),
+        name: 'perf-month',
+        meta: { title: 'perf-month', noCache: true }
+      },
+      {
+        path: 'perf-adjustment',
+        component: () => import('@/views/bonus/perf-adjustment'),
+        name: 'perf-adjustment',
+        meta: { title: 'perf-adjustment', noCache: true }
+      }
+    ]
+  },
   {
     path: '/tab',
     component: Layout,

+ 1 - 2
src/views/article/edit.vue

@@ -58,12 +58,11 @@ export default {
   mounted() {
     if (this.$route.name === 'edit') {
       fetchArticleDetail(this.$route.params.ID).then(response => {
-        console.log(response)
         this.form.title = response.data.oneData.TITLE
         this.form.cid = response.data.oneData.CID
         this.form.content = response.data.oneData.CONTENT
         this.form.sort = response.data.oneData.SORT
-        this.allCategory = response.allCategory
+        this.allCategory = response.data.allCategory
         this.loading = false
         this.isEdit = true
       })

+ 259 - 0
src/views/bonus/balance-list.vue

@@ -0,0 +1,259 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        ref="multipleTable"
+        class="table-box"
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :summary-method="getSummaries"
+        show-summary
+        :height="tool.getTableHeight()"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column v-if="tableHeaders" type="selection" width="70" />
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+
+      </el-table>
+      <div class="white-box-footer">
+        <!--<el-button type="primary" size="small" @click="handleSendShow" icon="el-icon-plus"-->
+        <!--v-show="permission.hasPermission(`bonus/cf-lx-apply`)">年度奖申请发放-->
+        <!--</el-button>-->
+        <el-button v-show="permission.hasPermission(`bonus/balance-export`)" type="success" size="small" @click="handleExport"><!-- 导出Excel -->Export Excel</el-button>
+        <pagination
+          :total="totalCount"
+          :page_size="pageSize"
+          @size-change="handleSizeChange"
+          @current-change="handleCurrentChange"
+        />
+      </div>
+    </div>
+    <!--<el-dialog v-loading="dialogLoading" title="Annual award distribution" :visible.sync="dialogVisible"><!-- 年度奖发放
+      <el-form :model="form" label-width="250px" class="form-dialog">
+        <el-form-item label="Distribution type"><!-- 发放类型
+          <el-select v-model="form.sendType" placeholder="Please select the distribution type"><!-- 请选择发放类型
+            <el-option
+              v-for="(item,index) in applyTypes"
+              :key="index"
+              :label="item.NAME"
+              :value="item.ID"
+            />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="Include member status"><!-- 包含会员状态
+          <el-select v-model="form.statusValue" placeholder="Please select a status" multiple><!-- 请选择状态
+            <el-option v-for="(item,key) in statuses" :key="key" :label="item.label" :value="item.value" />
+          </el-select>
+        </el-form-item>
+        <el-form-item label="Remark"><!-- 备注
+          <el-input v-model="form.remark" type="textarea" :row="2" placeholder="Please enter the content"><!-- 请输入内容 </el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="dialogVisible = false"><!-- 取消 cancel</el-button>
+        <el-button type="primary" @click.native="handleSend"><!-- 发放 grant</el-button>
+      </div>
+    </el-dialog>
+    </el-dialog> -->
+  </div>
+</template>
+
+<script>
+import { fetchGetUserStatus, fetchBalanceList, fetchBalanceExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'BonusBalanceList',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      tableHeight: window.innerHeight - 310,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {},
+      dialogVisible: false,
+      dialogLoading: false,
+      statuses: null,
+      applyTypes: [
+        { 'ID': 'all', 'NAME': 'All' }, // 全部
+        { 'ID': 'cf', 'NAME': 'Garage endowment' }, // 车房养老
+        { 'ID': 'lx', 'NAME': 'Leader bonus' }// 领袖分红
+      ],
+      form: {
+        selectedIds: [],
+        statusValue: [],
+        sendType: null,
+        remark: null
+      }
+    }
+  },
+  mounted() {
+    fetchGetUserStatus().then(response => {
+      this.statuses = response.data.statuses
+      return this.getData()
+      // Just to simulate the time of the request
+    })
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchBalanceList(paramsData).then(response => {
+        console.log(response)
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        this.sumData = response.data.sumData
+        this.loading = false
+      })
+    },
+    // handleSendShow() {
+    //   if (this.multipleSelection.length < 1) {
+    //     this.$message({
+    //       message: 'Please check the member to apply for distribution', // 请勾选要申请发放的会员
+    //       type: 'warning'
+    //     })
+    //     return false
+    //   }
+    //   this.dialogVisible = true
+    // },
+    // handleSend() {
+    //   this.dialogLoading = true
+    //   this.$message({
+    //     message: 'Applying for distribution, please wait', // 正在申请发放请稍后
+    //     type: 'info'
+    //   })
+    //   for (const val of this.multipleSelection) {
+    //     this.form.selectedIds.push(val.USER_ID)
+    //   }
+    //   network.postData(`bonus/cf-lx-apply`,
+    //     this.form
+    //   ).then(response => {
+    //     this.$message({
+    //       message: response,
+    //       type: 'success'
+    //     })
+    //     this.dialogVisible = false
+    //     this.dialogLoading = false
+    //     this.form = {
+    //       selectedIds: [],
+    //       year: null,
+    //       sendType: null,
+    //       remark: null
+    //     }
+    //     this.getData()
+    //   }).catch(response => {
+    //     this.dialogLoading = false
+    //   })
+    // },
+    getSummaries(param) {
+      const { columns, data } = param
+      const sums = []
+      if (columns && data && columns.length > 0 && data.length > 0) {
+        columns.forEach((column, index) => {
+          if (index === 0) {
+            sums[index] = 'sub-total' + '\n' + 'Total' // '小计' + "\n" + '合计'
+            return
+          }
+          const values = data.map(item => {
+            if (typeof item[column.property] === 'object') {
+              return Number(item[column.property].value)
+            } else {
+              return Number(undefined)
+            }
+          })
+          if (!values.every(value => isNaN(value))) {
+            sums[index] = values.reduce((prev, curr) => {
+              const value = Number(curr)
+              if (!isNaN(value)) {
+                return prev + curr
+              } else {
+                return prev
+              }
+            }, 0)
+            const field = 'SUM_' + column.property
+            if (typeof this.sumData[field] !== 'undefined') {
+              sums[index] = tool.formatPrice(sums[index]) + '\n' + tool.formatPrice(this.sumData[field])
+            } else {
+              sums[index] = tool.formatPrice(sums[index])
+            }
+          } else {
+            sums[index] = '-'
+          }
+        })
+      }
+      return sums
+    },
+    handleExport() {
+      this.$confirm(`Are you sure you want to export the current data?`, 'Hint', { // `确定要导出当前数据吗?`, '提示',
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchBalanceExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+
+      })
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+</style>

+ 121 - 0
src/views/bonus/flow-bonus.vue

@@ -0,0 +1,121 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table ref="multipleTable" class="table-box" :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()">
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/flow-bonus-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchFlowBonus, fetchFlowBonusExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '../../components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'BonusFlowBonus',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {}
+    }
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchFlowBonus(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        // vueObj.sumData = response.sumData
+      })
+    },
+    handleExport() {
+      this.$confirm(`Are you sure you want to export the current data?`, 'Hint', { // `确定要导出当前数据吗?`, '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchFlowBonusExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+
+      })
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+  .table-box .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .table-box .el-form-item {
+    width: 30%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 176 - 0
src/views/bonus/other-period-bonus.vue

@@ -0,0 +1,176 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user :filter-types.sync="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table ref="multipleTable" class="table-box" :data="tableData" stripe style="width: 100%;" :height="tool.getTableHeight()">
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/new-period-bonus-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchOtherPeriodBonusFilterTypes, fetchOtherPeriodBonus, fetchOtherPeriodBonusExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import baseInfo from '@/utils/baseInfo'
+import Pagination from '@/components/Pagination'
+import filterHelper from '../../utils/filterHelper'
+
+export default {
+  name: 'BonusOtherPeriodBonus',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      sumData: {
+        'SUM_PV_1L': null
+      },
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      filterTypes: null,
+      filterModel: {},
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels()
+    }
+  },
+  mounted() {
+    this.loading = false
+    this.getData()
+  },
+  methods: {
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    handleFilter() {
+      this.getData()
+    },
+    getFilterTypes() {
+      fetchOtherPeriodBonusFilterTypes.then(response => {
+        this.filterTypes = response.data
+        // 如果地址栏不为空则执行getData()
+        // if(window.location.href.match(/filter=/) !== null){
+        this.getData()
+        // }
+      })
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchOtherPeriodBonus(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        this.loading = false
+        // vueObj.sumData = response.sumData
+      })
+    },
+    getSummaries(param) {
+      const { columns, data } = param
+      const sums = []
+      if (columns && data && columns.length > 0 && data.length > 0) {
+        columns.forEach((column, index) => {
+          if (index === 0) {
+            sums[index] = 'sub-total' + '\n' + 'Total' // '小计' + "\n" + '合计'
+            return
+          }
+          const values = data.map(item => {
+            if (typeof item[column.property] === 'object') {
+              return Number(item[column.property].value)
+            } else {
+              return Number(undefined)
+            }
+          })
+          if (!values.every(value => isNaN(value))) {
+            sums[index] = values.reduce((prev, curr) => {
+              const value = Number(curr)
+              if (!isNaN(value)) {
+                return prev + curr
+              } else {
+                return prev
+              }
+            }, 0)
+            const field = 'SUM_' + column.property
+            if (typeof this.sumData[field] !== 'undefined') {
+              sums[index] = tool.formatPrice(sums[index]) + '\n' + tool.formatPrice(this.sumData[field])
+            } else {
+              sums[index] = tool.formatPrice(sums[index])
+            }
+          } else {
+            sums[index] = '-'
+          }
+        })
+      }
+      return sums
+    },
+    handleExport() {
+      this.$confirm(`Are you sure you want to export the current data?`, 'Hint', { // `确定要导出当前数据吗?`, '提示',
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchOtherPeriodBonusExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+
+      })
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+  .table-box .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .table-box .el-form-item {
+    width: 30%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 150 - 0
src/views/bonus/perf-adjustment.vue

@@ -0,0 +1,150 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-user" @keyup.enter="getData()">
+        <el-input v-model="memberCode" size="small" style="width:400px;">
+          <template slot="prepend">Member Code</template>
+        </el-input>
+        <el-button type="primary" icon="el-icon-search" size="small" @click="getData()">Confirm<!-- 确定 --></el-button>
+      </div>
+
+      <div v-show="show" style="margin-top: 25px;">
+        <el-row>
+          <el-col :span="16">
+            <div class="grid-content bg-purple" style="width: 100%">
+              <el-card class="box-card" shadow="hover">
+                <el-form ref="perfForm" :model="perfForm" status-icon label-width="250px" width="100%" class="demo-ruleForm">
+                  <el-form-item v-show="false" label="Member Code" prop="USER_NAME">
+                    <el-input v-model="perfForm.USER_ID" type="text" size="small" />
+                    <el-input v-model="perfForm.USER_NAME" type="text" size="small" />
+                  </el-form-item>
+
+                  <el-divider><span style="font-weight: bold;">L. Market Balance Performance</span></el-divider>
+                  <el-form-item label="Member Code" prop="SURPLUS_1L_USER_NAME"><!--会员编号-->
+                    <el-input v-model="perfForm.SURPLUS_1L_USER_NAME" type="text" size="small" autocomplete="off" readonly />
+                  </el-form-item>
+                  <el-form-item label="Balance Performance" prop="SURPLUS_1L"><!--综合结余业绩-->
+                    <el-input v-model="perfForm.SURPLUS_1L" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+                  <el-form-item label="Entry Balance Performance" prop="SURPLUS_1L_ZC"><!--首单结余业绩-->
+                    <el-input v-model="perfForm.SURPLUS_1L_ZC" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+                  <el-form-item label="Reconditioning Balance Performance" prop="SURPLUS_1L_FX"><!--复消结余业绩-->
+                    <el-input v-model="perfForm.SURPLUS_1L_FX" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+
+                  <el-divider><span style="font-weight: bold;">R. Market Balance Performance</span></el-divider>
+                  <el-form-item label="Member Code" prop="SURPLUS_2L_USER_NAME"><!--会员编号-->
+                    <el-input v-model="perfForm.SURPLUS_2L_USER_NAME" type="text" size="small" autocomplete="off" readonly />
+                  </el-form-item>
+                  <el-form-item label="Balance Performance" prop="SURPLUS_2L"><!--综合结余业绩-->
+                    <el-input v-model="perfForm.SURPLUS_2L" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+                  <el-form-item label="Entry Balance Performance" prop="SURPLUS_2L_ZC">
+                    <el-input v-model="perfForm.SURPLUS_2L_ZC" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+                  <el-form-item label="Reconditioning Balance Performance" prop="SURPLUS_2L_FX"><!--复消结余业绩-->
+                    <el-input v-model="perfForm.SURPLUS_2L_FX" type="text" size="small" autocomplete="off" />
+                  </el-form-item>
+
+                  <el-form-item>
+                    <el-button type="primary" size="small" @click="handlePerfAdjustment('perfForm')">Save</el-button>
+                  </el-form-item>
+                </el-form>
+              </el-card>
+            </div>
+          </el-col>
+        </el-row>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+import { fetchPerfAdjustment, fetchPerfAdjustmentPost } from '@/api/bonus'
+
+export default {
+  name: 'BonusPerfAdjustment',
+  data() {
+    return {
+      loading: false,
+      memberCode: '',
+      show: false,
+      perfForm: {
+        USER_ID: '',
+        USER_NAME: '',
+        SURPLUS_1L: '',
+        SURPLUS_1L_ZC: '',
+        SURPLUS_1L_FX: '',
+        SURPLUS_21L_USER_NAME: '',
+        SURPLUS_2L: '',
+        SURPLUS_2L_ZC: '',
+        SURPLUS_2L_FX: '',
+        SURPLUS_2L_USER_NAME: ''
+      }
+    }
+  },
+  methods: {
+    // 查询安置网的下级会员和业绩
+    getData() {
+      if (!this.memberCode.length) {
+        this.$message({
+          message: 'Please enter member code',
+          type: 'info'
+        })
+        return false
+      }
+
+      // 清除上一次的填充结果
+      this.$refs['perfForm'].resetFields()
+      this.show = false
+
+      fetchPerfAdjustment({ memberCode: this.memberCode }).then(response => {
+        this.perfForm = response.data.allData
+        this.show = true
+        this.loading = false
+        // vueObj.sumData = response.sumData
+      }).catch(error => {
+        this.$message({
+          message: error,
+          type: 'warning'
+        })
+
+        this.loading = false
+      })
+    },
+    // 修改会员业绩
+    handlePerfAdjustment(formName) {
+      this.$confirm('Confirm and revise member performance?', 'Hits', { // 确认修改会员业绩
+        confirmButtonText: 'Confirm',
+        cancelButtonText: 'Cancel',
+        type: 'warning'
+      }).then(() => {
+        this.loading = true
+        return fetchPerfAdjustmentPost(this.perfForm).then(response => {
+          this.$message({
+            message: response.data,
+            type: 'success'
+          })
+          this.loading = false
+
+          // 刷新数据
+          this.getData()
+        }).catch(error => {
+          this.$message({
+            message: error,
+            type: 'warning'
+          })
+          this.loading = false
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style>
+  .filter-user { font-size: 14px; margin-bottom: 20px; }
+  .filter-user:after { content: ''; display: table;  clear: both; }
+</style>

+ 139 - 0
src/views/bonus/perf-month.vue

@@ -0,0 +1,139 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :height="tool.getTableHeight(true)"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column v-if="tableHeaders" type="selection" width="55" />
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/perf-month-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchPerfMonth, fetchPerfMonthExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'LeoPerfMonthTable',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {},
+      filterStatus: 'ALL'
+    }
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchPerfMonth(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        // vueObj.sumData = response.sumData
+      })
+    },
+    handleExport() {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+      this.$confirm('Are you sure you want to export the data in the current table?', 'Hint', { // '确定要导出当前表格中的数据吗?', '提示',
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchPerfMonthExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+      })
+    }
+  }
+}
+</script>
+
+<style>
+  .leo-withdrawTable .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .leo-withdrawTable .el-form-item {
+    width: 40%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 146 - 0
src/views/bonus/perf-order.vue

@@ -0,0 +1,146 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <el-tabs v-model="filterStatus" @tab-click="handleFilterStatusClick">
+        <el-tab-pane label="All" name="ALL" :lazy="true" /><!-- 全部 -->
+        <el-tab-pane label="Welcome Pack Order" name="ZC" :lazy="true" /><!-- 首购单 -->
+      </el-tabs>
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :height="tool.getTableHeight(true)"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column v-if="tableHeaders" type="selection" width="55" />
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/perf-order-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchPerfOrder, fetchPerfOrderExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'LeoPerfOrderTable',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {},
+      filterStatus: 'ALL'
+    }
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleFilterStatusClick(tab, event) {
+      filterHelper.clearFilterOption(this)
+      this.getData()
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchPerfOrder(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        // vueObj.sumData = response.sumData
+      })
+    },
+    handleExport() {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+      this.$confirm('Are you sure you want to export the data in the current table?', 'Hint', { // '确定要导出当前表格中的数据吗?', '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchPerfOrderExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+      })
+    }
+  }
+}
+</script>
+
+<style>
+  .leo-withdrawTable .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .leo-withdrawTable .el-form-item {
+    width: 40%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 139 - 0
src/views/bonus/perf-period-list.vue

@@ -0,0 +1,139 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :height="tool.getTableHeight(true)"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column v-if="tableHeaders" type="selection" width="55" />
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/perf-period-list-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchPerfPeriodList, fetchPerfPeriodListExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'LeoPerfPeriodListTable',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {},
+      filterStatus: 'ALL'
+    }
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchPerfPeriodList(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        // vueObj.sumData = response.sumData
+      })
+    },
+    handleExport() {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+      this.$confirm('Are you sure you want to export the data in the current table?', 'Hint', { // '确定要导出当前表格中的数据吗?', '提示',
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchPerfPeriodListExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+      })
+    }
+  }
+}
+</script>
+
+<style>
+  .leo-withdrawTable .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .leo-withdrawTable .el-form-item {
+    width: 40%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 137 - 0
src/views/bonus/user-perf.vue

@@ -0,0 +1,137 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <div class="filter-box">
+        <filter-user ref="filterUser" :filter-types="filterTypes" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :height="tool.getTableHeight(true)"
+        @selection-change="handleSelectionChange"
+      >
+        <el-table-column v-for="(tableHeader, key) in tableHeaders" :key="key" :label="tableHeader.header" :width="tableHeader.other.width ? tableHeader.other.width : ''" :prop="tableHeader.other.prop ? tableHeader.other.prop : null">
+          <template slot-scope="scope">
+            <template v-if="scope.row[tableHeader.index].other.tag">
+              <el-tag :type="scope.row[tableHeader.index].other.tag.type ? scope.row[tableHeader.index].other.tag.type : null" :size="scope.row[tableHeader.index].other.tag.size ? scope.row[tableHeader.index].other.tag.size : null" :class="scope.row[tableHeader.index].other.tag.class ? scope.row[tableHeader.index].other.tag.class : null">{{ scope.row[tableHeader.index].value }}</el-tag>
+            </template>
+            <template v-else>
+              <div v-html="scope.row[tableHeader.index].value" />
+            </template>
+          </template>
+        </el-table-column>
+      </el-table>
+      <div class="white-box-footer">
+        <el-button v-show="permission.hasPermission(`bonus/user-perf-export`)" type="success" size="small" @click="handleExport">Export Excel<!-- 导出Excel --></el-button>
+        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { fetchUserPerf, fetchUserPerfExport } from '@/api/bonus'
+import tool from '@/utils/tool'
+import baseInfo from '@/utils/baseInfo'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '@/utils/filterHelper'
+
+export default {
+  name: 'LeoUserPerfTable',
+  components: { FilterUser, Pagination },
+  data() {
+    return {
+      tableHeaders: null,
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      permission: permission,
+      baseDecLevels: baseInfo.decLevels(),
+      baseEmpLevels: baseInfo.empLevels(),
+      filterTypes: null,
+      filterModel: {},
+      filterStatus: 'ALL'
+    }
+  },
+  mounted() {
+    this.getData()
+  },
+  methods: {
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    getData(page, pageSize) {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+
+      this.loading = true
+      const paramsData = Object.assign({
+        page: (page === null || page === undefined) ? 1 : page,
+        pageSize: (pageSize === null || pageSize === undefined) ? this.pageSize : pageSize
+      }, filterData)
+      fetchUserPerf(paramsData).then(response => {
+        this.filterTypes = response.data.filterTypes
+        this.tableData = response.data.list
+        this.tableHeaders = response.data.columnsShow ? response.data.columnsShow : []
+        this.loading = false
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+      })
+    },
+    handleExport() {
+      const filterData = this.filterModel
+      if (window.location.href.indexOf('filter') === -1) {
+        filterData.filterType = this.filterStatus !== 'ALL' ? `=,${this.filterStatus}` : ''
+      }
+      this.$confirm('Are you sure you want to export the data in the current table?', 'Hint', { // '确定要导出当前表格中的数据吗?', '提示',
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return fetchUserPerfExport(this.filterModel)
+      }).then(response => {
+        this.$message({
+          message: response.data,
+          type: 'success'
+        })
+      }).catch(response => {
+      })
+    }
+  }
+}
+</script>
+
+<style>
+  .leo-withdrawTable .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .leo-withdrawTable .el-form-item {
+    width: 40%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 301 - 0
src/views/file/export.vue

@@ -0,0 +1,301 @@
+<template>
+  <div v-loading="loading">
+    <div class="white-box">
+      <el-tabs v-model="moduleName" @tab-click="handleFilterStatusClick">
+        <el-tab-pane label="All" name="all" :lazy="true" /><!-- 全部 -->
+        <el-tab-pane
+          v-for="(item,key) in allModuleName"
+          :key="key"
+          :label="item.label"
+          :name="item.value"
+          :lazy="true"
+        />
+      </el-tabs>
+      <div class="filter-box">
+        <filter-user :filter-types.sync="filterTypes" :filter-btn-name="$t('common.screen')" @select-value="handleFilterUser" />
+      </div>
+      <el-table
+        ref="multipleTable"
+        class="table-box"
+        :data="tableData"
+        stripe
+        style="width: 100%;"
+        :height="tool.getTableHeight(true)"
+        @selection-change="handleSelectionChange"
+      >
+        <!--        <el-table-column type="selection" width="55"></el-table-column>-->
+        <!-- <el-table-column
+          :label="$t('file.exportName')"
+          prop="EXPORT_NAME"
+          :width="flexWidth('EXPORT_NAME',tableData,$t('file.exportName'))"
+        > --><!-- 导出名称 -->
+        <el-table-column
+          :label="$t('file.exportName')"
+          prop="EXPORT_NAME"
+          :width="flexWidth('EXPORT_NAME',tableData,$t('file.exportName'))"
+        >
+          <!-- <template slot-scope="scope">
+            {{ scope.row.EXPORT_NAME }}
+          </template> -->
+
+        </el-table-column>
+        <el-table-column
+          :label="$t('file.route')"
+          prop="EXPORT_PERCENT"
+          :width="flexWidth('EXPORT_PERCENT',tableData,$t('file.download'))"
+        ><!-- 路径 -->
+          <template slot-scope="scope">
+            <el-button
+              v-if="Number(scope.row.EXPORT_PERCENT)===100"
+              type="success"
+              size="small"
+              @click="singleDownload(scope.row)"
+            >{{ $t('file.download') }}
+            </el-button>
+          </template>
+        </el-table-column>
+        <el-table-column
+          :label="$t('file.operationAdministrator')"
+          prop="ADMIN_NAME"
+          :width="flexWidth('ADMIN_NAME',tableData,$t('file.operationAdministrator'))"
+        ><!-- 操作管理员 -->
+          <!-- <template slot-scope="scope">
+            {{ scope.row.ADMIN_NAME }}
+          </template> -->
+        </el-table-column>
+        <el-table-column
+          :label="$t('file.exportProgress')"
+          prop="EXPORT_PERCENT"
+          :width="flexWidth('EXPORT_PERCENT',tableData,$t('file.exportProgress'))"
+        ><!-- 导出进度 -->
+          <template slot-scope="scope">
+            <el-progress
+              type="circle"
+              :percentage="Number.parseInt(percentList['EXPORT_PERCENT'][scope.row.ID])"
+              :width="50"
+              :stroke-width="3"
+            />
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('file.exportStart')" width="180"><!-- 导出开始 -->
+          <template slot-scope="scope">
+            {{ tool.formatDate(scope.row.STARTED_AT) }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('file.exportComplete')" width="180"><!-- 导出完成 -->
+          <template slot-scope="scope">
+            {{ tool.formatDate(scope.row.ENDED_AT) }}
+          </template>
+        </el-table-column>
+        <el-table-column :label="$t('file.createTime')" width="180"><!-- 创建时间 -->
+          <template slot-scope="scope">
+            {{ tool.formatDate(scope.row.CREATED_AT) }}
+          </template>
+        </el-table-column>
+          <!--        <el-table-column fixed="right" label="操作" width="180">-->
+          <!--          <template slot-scope="scope">-->
+          <!--            <el-dropdown size="small" trigger="click" v-if="permission.hasPermission(`file/export-delete`)">-->
+          <!--              <el-button type="primary" size="small" @click.stop="">-->
+          <!--                操作该数据<i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
+          <!--              </el-button>-->
+          <!--              <el-dropdown-menu slot="dropdown">-->
+          <!--                <el-dropdown-item command="delete" @click.native="handleDelete(scope.row)">删除</el-dropdown-item>-->
+          <!--              </el-dropdown-menu>-->
+          <!--            </el-dropdown>-->
+          <!--          </template>-->
+          <!--        </el-table-column>-->
+        </el-table-column>
+      </el-table>
+      <!--      <div class="white-box-footer"
+      >-->
+      <!--        <el-dropdown size="small" trigger="click" v-if="permission.hasPermission(`file/export-delete`)">-->
+      <!--          <el-button type="primary" size="small">-->
+      <!--            所选数据<i class="el-icon-arrow-down el-icon&#45;&#45;right"></i>-->
+      <!--          </el-button>-->
+      <!--          <el-dropdown-menu slot="dropdown">-->
+      <!--            <el-dropdown-item command="delete" @click.native="handleDelete()">删除</el-dropdown-item>-->
+      <!--          </el-dropdown-menu>-->
+      <!--        </el-dropdown>-->
+      <!--        <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange"-->
+      <!--                    @current-change="handleCurrentChange"></pagination>-->
+      <!--      </div>-->
+    </div>
+  </div>
+</template>
+
+<script>
+import tool from '@/utils/tool'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import filterHelper from '../../utils/filterHelper'
+import { fetchExport } from '@/api/file'
+import store from '@/utils/vuexStore'
+
+export default {
+  name: 'FileExport',
+  components: { FilterUser },
+  data() {
+    return {
+      tableData: null,
+      multipleSelection: [],
+      loading: true,
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 20,
+      tool: tool,
+      EXPORT_NAME: '',
+      permission: permission,
+      filterTypes: {
+        'EXPORT_NAME': { isUserTable: false, name: this.$t('file.exportName') }, // 导出名称
+        'STARTED_AT': { isUserTable: false, name: this.$t('file.exportStartTime'), other: 'date' }, // 导出开始时间
+        'ENDED_AT': { isUserTable: false, name: this.$t('file.exportEndTime'), other: 'date' }, // 导出结束时间
+        'createdAt': { isUserTable: false, name: this.$t('file.creationTime'), other: 'date' }// 创建时间
+      },
+      filterModel: {},
+      filterStatus: '0',
+      auditStatus: ['not approved', 'approved', 'rejected'], // '未审核', '已审核', '已拒绝'
+      allModuleName: null,
+      moduleName: 'all',
+      percentList: {
+        'EXPORT_PERCENT': {}
+      }
+    }
+  },
+  mounted() {
+    this.getData()
+    store.state.socket.onMessageCallback = this.onMessageCallback
+  },
+  methods: {
+    singleDownload(row) {
+      const url = (row.REMOTE_URL) ? row.REMOTE_URL : process.env.VUE_APP_CDN_API + '/' + 'upload/excel_export' + '/' + row.FILE_NAME
+      window.open(url)
+    },
+    handleSelectionChange(val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange(page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange(pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleDownload(url) {
+      window.open(url)
+    },
+    handleFilterStatusClick(tab, event) {
+      this.getData()
+    },
+    handleFilterUser(filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    handleFilter() {
+      this.getData()
+    },
+    getData(page, pageSize) {
+      if (page === undefined) page = 1
+      if (pageSize === undefined) pageSize = 20
+      const filterData = this.filterModel
+      filterData.moduleName = this.moduleName !== 'all' ? `=,${this.moduleName}` : ''
+      let paramsData = {
+        page: page,
+        pageSize: pageSize
+      }
+      paramsData = Object.assign(paramsData, filterData)
+      console.log(paramsData)
+      fetchExport(paramsData).then(response => {
+        this.allModuleName = response.data.allModuleName
+        this.tableData = response.data.list
+        console.log(this.tableData)
+        this.currentPage = page
+        this.totalPages = parseInt(response.data.totalPages)
+        this.totalCount = parseInt(response.data.totalCount)
+        this.pageSize = pageSize
+        this.loading = false
+        const EXPORT_PERCENT = ['EXPORT_PERCENT']
+        if (EXPORT_PERCENT !== null) {
+          if (EXPORT_PERCENT.length > 0) {
+            for (const i in this.tableData) {
+              for (const j in EXPORT_PERCENT) {
+                this.$set(this.percentList[EXPORT_PERCENT[j]], this.tableData[i].ID, this.tableData[i][EXPORT_PERCENT[j]])
+              }
+            }
+          }
+        }
+      }, null, ['EXPORT_PERCENT'])
+    },
+    onMessageCallback(data) {
+      console.log(data)
+      if (data) {
+        if (data.other && data.other.MODEL === 'EXPORT' && data.other.ID) {
+          this.$set(this.percentList[data.other.FIELD], data.other.ID, data.percent)
+        }
+        if (data.percent && data.percent === 100) {
+          this.getData(this.currentPage, this.pageSize)
+        }
+      }
+    },
+    /**
+     * flexWidth
+     * @param prop 每列的prop 可传''
+     * @param tableData 表格数据
+     * @param title 标题长内容短的,传标题  可不传
+     * @param num 列中有标签等加的富余量
+     * @returns 列的宽度
+     * 注:prop,title有一个必传
+     */
+    flexWidth(prop, tableData = '', title, num = 0) {
+      if (tableData === undefined || tableData === null) {
+        return
+      }
+      let flexWidth = 0// 初始化表格列宽
+      let columnContent = ''// 占位最宽的内容
+      const canvas = document.createElement('canvas')
+      const context = canvas.getContext('2d')
+      context.font = '14px Microsoft YaHei'
+      if ((prop === '') && title) { // 标题长内容少的,取标题的值,
+        columnContent = title
+      } else { // 获取该列中占位最宽的内容
+        let index = 0
+        for (let i = 0; i < Object.values(tableData).length; i++) {
+          const now_temp = tableData[i][prop] + ''
+          const max_temp = tableData[index][prop] + ''
+          const now_temp_w = context.measureText(now_temp).width
+          const max_temp_w = context.measureText(max_temp).width
+          if (now_temp_w > max_temp_w) {
+            index = i
+          }
+        }
+        if (tableData[index] === undefined || tableData[index] === null) {
+          return
+        }
+        columnContent = tableData[index][prop]
+        // 比较占位最宽的值跟标题、标题为空的留出四个位置
+        const column_w = context.measureText(columnContent).width
+        const title_w = context.measureText(title).width
+        if (column_w < title_w) {
+          columnContent = title || '留四个字'
+        }
+      }
+      // 计算最宽内容的列宽
+      const width = context.measureText(columnContent)
+      flexWidth = width.width + 40 + num
+      return flexWidth + 'px'
+    }
+  }
+}
+
+</script>
+
+<style scoped>
+  .table-box .el-form-item__label {
+    width: 100px;
+    color: #99a9bf;
+  }
+
+  .table-box .el-form-item {
+    width: 30%;
+    margin-right: 0;
+    margin-bottom: 0;
+  }
+</style>

+ 1 - 1
src/views/log/user-login.vue

@@ -103,7 +103,7 @@ export default {
         return fetchUserLoginExport(this.filterModel)
       }).then(response => {
         this.$message({
-          message: response,
+          message: response.data,
           type: 'success'
         })
       }).catch(response => {