前端项目:使用handsontable画一个表格

主页面

<template>
  <!-- 内容区域 -->
  <div class="sal-rpt-unit-grant">
    <!-- 单位头部开始 -->
    <div class="mt5 fix">
      <!-- 单位 -->
      <v-agy-select v-model="query.agy"></v-agy-select>
      <div class="r">
        <span v-if="isSystemPermission()">提示:当前为操作系统级数据权限(单位代码='*')</span>
        <slot name="toolbar">
          <el-button-group>
            <el-button type="primary" size="mini" @click="handleRefresh">刷新</el-button>
            <el-button type="primary" size="mini" @click="handleExport">导出</el-button>
          </el-button-group>
        </slot>
      </div>
    </div>
    <!-- 单位头部结束 -->
    <!-- 部门树和表格开始 -->
    <div>
      <el-row :gutter="10">
        <el-col :span="6" v-show="!isFullScreen">
          <!-- 左边搜索框和部门树开始 -->
          <div class="left" style="border-radius: 4px;padding: 1px;overflow: auto;height:480px;border:1px solid #ccc;">
            <div class="tcontent" style="margin-bottom:10px;">
              <el-input placeholder="输入关键字进行过滤" size="small" v-model="filterText">
                <el-button slot="append" icon="el-icon-search"></el-button>
              </el-input>
              <el-tree id="tree" class="filter-tree" :data="treeDataBm" show-checkbox node-key="id" :props="{id: 'madCode',label: 'madName',children: 'children'}" default-expand-all :filter-node-method="filterNode" :check-on-click-node="true" :expand-on-click-node="false" :check-strictly="false" @check-change="handleCheckChange" ref="tree2">
              </el-tree>
            </div>
          </div>
          <!-- 左边搜索框和部门树结束 -->
        </el-col>
        <el-col :span="!isFullScreen ? 18 : 24">
          <!-- 右边表格开始 -->
          <div class="right bs-bg-color-white p0">
            <!-- 右边表格顶部查询条件开始 -->
            <div style="border-top-left-radius: 4px;border-top-right-radius: 4px;overflow: auto;height:28px;border:1px solid #ccc;border-right:1px solid #ccc;border-top:1px solid #ccc;border-bottom:1px solid #ccc;">
              <span class="ml5 search" style="font-size:12px;float:left">
                <span class="mr1 mt5" style="font-size:12px;">
                  年度:
                  <el-select v-model="currentYear" filterable placeholder="请选择" size="mini" class="ml1 fl" style="width: 70px;" @change="handleYearChange">
                    <el-option v-for="item in yearData" :key="item.year" :label="item.year" :value="item.year">
                    </el-option>
                  </el-select>
                </span>
                  <span class="mr1 mt5" style="font-size:12px;">
                  月份:
                  <el-select v-model="currentMo" filterable placeholder="请选择" size="mini" class="ml1 fl"
                             style="width: 60px;" @change="handleMoChange">
                    <el-option
                      v-for="item in fromMoOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value">
                    </el-option>
                  </el-select>
                </span>
                <span class="mr1 mt5" style="font-size:12px;">
                  至
                  <el-select v-model="toMo" filterable placeholder="请选择" size="mini" class="ml1 fl"
                             style="width: 60px;" @change="handleMoChange">
                    <el-option
                      v-for="item in toMoOptions"
                      :key="item.value"
                      :label="item.label"
                      :value="item.value">
                    </el-option>
                  </el-select>
                </span>
                <span class="ml1">
                  <span class="ml1" style="font-size:12px;">工资类别:</span>
                  <el-select v-model="currentSalTypeCode" filterable placeholder="请选择" size="mini" class="ml10 fl" style="width: 120px;left:-10px;"
                             @change="handleTypeChange">
                    <el-option
                      v-for="item in salTypeFilterData"
                      :key="item.typeCode"
                      :label="item.typeName"
                      :value="item.typeCode">
                    </el-option>
                  </el-select>
                </span>
                <span style="font-size:12px;">检索:</span>
                <el-input class="pl1" placeholder="请输入人员代码或名称" id="searchField1" size="mini" @clear="handleSearchClear"
                          v-model="searchText" clearable style="width: 240px;">
                </el-input>
              </span>
            </div>
            <!--右边表格顶部查询条件结束 -->
            <!--hansonTable区域开始-->
            <div class="mt1 hanson-table" style="padding: 0px;overflow: auto;border:1px solid #ccc;border-bottom:1px solid #ccc;border-right:2px solid #ccc;border-top:0px solid #ccc;">
              <div id="calcTable">
              </div>
            </div>
            <!--hansonTable区域结束-->
            <div class="fix bs-table-foot">
            </div>
            <div id="deptPrintTable"></div>
          </div>
        </el-col>
        <!-- 小手点击图片开始 -->
        <div class="bar-line-left">
          <span class="pfs-line-border poi bs-background-color-primary" @click.stop="handleFadeToggle"></span>
          <span class="pfs-icon1"><i @click.stop="handleFadeToggle" :class="['fa','poi','f28','dn',!isFullScreen ? ' fa-hand-o-left' : 'fa-hand-o-right']"></i></span>
        </div>
        <!-- 小手点击图片结束 -->
      </el-row>
    </div>
    <!-- 右表表格结束 -->
    <iframe ref="xlsxIframe" :src="PUBLIC_PATH + 'static/lib/xlsx/index.html' " style="display:none"></iframe>
  </div>
</template>
<script>
  import { mapGetters } from 'vuex';
  import { PUBLIC_PATH } from '@/assets/js/constant';
  import { GET_LOGIN_INFO, GET_CONTEXT_AGY_ACB } from '@/store/login';
  import { getMadInfo } from '@/mixin/agy';
  import { innerHeight, getEnumerate, download } from '@/mixin/page';
  import fetch from '@/config/fetch';
  import util from '@/assets/js/util';
  const handsontable = () => import(/*webpackChunkName: 'async_vendors/handsontable-pro' */ 'handsontable-pro');
  const fileSaver = () => import(/* webpackChunkName: 'async_vendors/file-saver' */ 'file-saver');
  import 'handsontable/dist/handsontable.full.css';
  import tableview from '../sal-pub/tableview';
  import sal from '../sal-pub/sal';
  import { hasView } from '@/mixin/system';
  import { CONTEXT_PATH } from '@/assets/js/constant';
  var tableData = [];
  var ff = [];
  export default {
    name: 'SAL_RPT_UNIT_GRANT',
    mixins: [innerHeight],
    data() {
      return {
        query: {
          //查询表格的参数
          agy: {
            madCode: '',
            madName: '',
          },
          isEnabled: 1,
          keyword: '',
          code: '', //部门code
        },
        filterText: '',
        treeDataBm: [], //部门树的数据
        tableData: [],
        searchText: '',
        isFullScreen: false,
        hot: null,
        deptPrintHots: null,
        salTypeData: [],
        currentYear: null,
        currentMo: null,
        toMo: null,
        currentSalType: {},
        currentSalTypeCode: null,//单选工资类别
        cellRender: null,
        nestedHeaders:[], //放合并数据,不能被注释掉
        yearData: null,
        currentSchema: null,
        madDataMap: {},
        sTypeCode: [],
        mad: {}, //调用$set添加属性
        currentSalItemCode: [],
        deptCodes: [],
        headerDatas: [],
        tableList: [],
        PUBLIC_PATH,
        dongtaijiyibiaotou: [],
        itemTableList: [],  //二级表头 其中 一级表头为unitGrantCode + unitGrantName ,二级表头为unitGrantCode不为空的工资项(itemCode,itemName)
      };
    },
    created() {
      const { agyCode, agyName } = this.GET_CONTEXT_AGY_ACB;
      this.query.agy.madCode = agyCode;
      this.query.agy.madName = agyName;
    },
    watch: {
      'query.agy'(val) {
        this.query.keyword = '';
        this.resetParam();
        getMadInfo(val.madCode).then((res = {}) => {
          this.$set(this.$data, 'mad', res);
        });
        this.init();
      },
      filterText(val) {
        this.$refs.tree2.filter(val);
      },
    },
    methods: {
      //初始化Handsontable资源
      async initResource() {
        try {
          let Handsontable = await handsontable();
          this.Handsontable = Handsontable.default;
          return true;
        } catch (err) {
          return Promise.reject(err);
        }
      },
      /**
       *页面初始化
       *1.发放表取历史数据,计算表取当前数据
       *2.先取年度,再取月份和类别,最后取工资数据
       */
      getPageInfo() {
        //从工资项和公式中获取到已经分好组的工资项
        this.getSalTypeYear();
        this.getItemTabelData();
        this.getTableData();
      },
      //递归获取最后一个子节点
      getLastChild(data) {
        if (data.children && data.children.length !== 0) {
          this.getLastChild(data.children[0]);
        } else {
          //默认值选中的值,和右侧的状态
          data.heightLight = 'heightLight';
          this.query.code = data.madCode;
        }
      },
      //获取部门
      getTreeBmMethod() {
        this.$loading();
        fetch.post('/mad/department/tree', {
          agyCode: sal.getAgyCode(this.query.agy.madCode),
          fiscal: sal.getFiscal(this.query.agy.madCode, this.GET_LOGIN_INFO.fiscal)
        }).then(({ data }) => {
          this.$loadingClose();
          if (data.length !== 0) {
            this.getLastChild(data[0]);
          }
          this.treeDataBm = data;
          tableview.rebuildMadName(this.treeDataBm);
        }).catch(({ msg }) => {
          this.$loadingClose();
          this.$message({
            type: 'error',
            message: msg,
          });
        });
      },
      filterNode(value, data) {
        //部门树需要的数据
        if (!value) {
          return true;
        }
        return data.madName.indexOf(value) !== -1;
      },
      nodeClick(data) {
        this.query.code = data.madCode;
      },
      async init() {
        await this.initResource();
        //部门
        this.getTreeBmMethod();
        //搜索框监听
        this.initListener();
        this.initCellRender();
        this.getPageInfo();
        // this.tableFilterMoData();
      },
      //handsontable表格配置
      initHandsontable() {
        this.destroyHots();
        let container = document.getElementById('calcTable');
        let sheet = {};
        sheet.colHeaders = true;
        sheet.tableHeight = this.tableHeight;
        sheet.colWidths = 100;  //设置所有列宽为150像素
        sheet.fixedColumnsLeft = 150; //固定几列
        sheet.columns = this.getTableColumns(this.tableList, true);   //this.tableList控制表头
        sheet.cellRender = this.cellRender;
        sheet.nestedHeaders = this.getNestedHeaders();
        sheet.data = this.tableFilterData;
        this.hot = new this.Handsontable(
          container,
          tableview.getHotUnitSetting(sheet)
        );
        $('[id=hot-display-license-info]').remove();
      },
      //构建表头
      getNestedHeaders(){
        let result = [];
        let table1 = [];
        let staticHeader = ['工资月份','单位编码','单位名称','姓名','身份证号','工资卡号','工资卡开户银行'];
        _.forEach(staticHeader,o=>{
          ff.push(o);
          let headerContainer = {};
          headerContainer.label = o;
          headerContainer.colspan = 1;
          table1.push(headerContainer);
        });
        let typeCodeList = [];//存放工资类别的集合
        _.forEach(this.salTypeData,o=>{
          typeCodeList.push(o.typeCode)
        })
        typeCodeList = _.uniqWith(typeCodeList, _.isEqual);
        let typeCodeIndex = [];//工资类别的下标
        typeCodeIndex = _.findLastIndex(typeCodeList, o=> {
          return o == this.currentSalTypeCode;
        })
        let aa = _.groupBy(this.itemTableList, 'typeCode');
        let bb = _.map(aa,(k,v)=>{
          if(v == this.currentSalTypeCode){
            return k;
          }
        });
        let cc = _.find(bb,o=>{
          return o !== undefined;
        })
        let obj = _.groupBy(cc, 'unitGrantName');
        _.forEach(obj, (v, k)=> {
          let col = {}
          col.label = k;
          col.colspan = v.length;
          table1.push(col);
          this.dongtaijiyibiaotou.push(col);
        });
        result.push(table1);
        let tables2 = [' ',' ',' ',' ',' ',' ',' '];
        _.forEach(obj,(v,k)=>{
          _.forEach(v,j=>{
            tables2.push(j.itemName);
            ff.push(j.itemName)
          })
        })
        result.push(tables2);
        ff = _.uniqWith(ff, _.isEqual);
        return result;
      },

      //千分位显示数据
      getTableColumns(itemList) {  //itemList里面放的是表头
        let columns = [];
        _.forEach(itemList, o =>{
          if (o.isEnabled === 0) {
            return;
          }
          let column = {};
          column.data = o.data;
          column.name = o.name;
          column.readOnly = o.readOnly;
          if (o.type == 'numeric') {
            column.type = 'numeric';
            column.allowInvalid = false;
            column.numericFormat = { pattern: '0,0.00' };
            column.strict = true;
          } else {
            column.type = 'text';
            column.readOnly = true;
          }
          columns.push(column);
        });
        return columns;
      },
      initListener() {
        let searchField = document.getElementById('searchField1');
        let that = this;
        that.Handsontable.dom.addEvent(searchField, 'keyup', function (event) {
          debounceFn2(this.value, event);
        });
        var debounceFn2 = that.Handsontable.helper.debounce(function (value,event) {
          that.reLoadData();
        },500);
      },
      //控制月份
      handleMoChange(v) {
        this.getSalTypeData();
      },
      handleFadeToggle() {
        this.isFullScreen = !this.isFullScreen;
        this.reRenderHot();
      },
      //点击左右小手,控制报表是否全屏显示
      getActiveHot() {
        return this.hot;
      },
      reRenderHot() {
        tableview.reRenderHot(this.getActiveHot());
      },
      //获取年
      getSalTypeYear() {
        this.$loading();
        fetch.get('/sal/type/his/getYear', {
          params: {
            agyCode: sal.getAgyCode(this.query.agy.madCode),
            mofDivCode: this.GET_LOGIN_INFO.mofDivCode
          },
        }).then(({ data }) => {
          this.$loadingClose();
          this.yearData = data;
          if (this.yearData.length > 0) {
            this.currentYear = this.yearData[0].year;
            this.handleYearChange();
          }
        }).catch(({ msg }) => {
          this.$loadingClose();
          this.$message({
            type: 'error',
            message: msg,
          });
        });
      },
      //获取工资类型
      getSalTypeData() {
        this.$loading();
        fetch.post('/sal/type/his/listVO', {
          agyCode: sal.getAgyCode(this.query.agy.madCode),
          mofDivCode: this.GET_LOGIN_INFO.mofDivCode,
          year: this.currentYear, //需要写活
        }).then(({ data }) =>{
          this.$loadingClose();
          this.salTypeData = data;
          //如果是没有设置单位自发工资项的类别,就不显示这个工资类别
          this.salTypeData = _.filter(this.salTypeData ,o=>{
            return _.indexOf(this.sTypeCode,o.typeCode) !== -1;
          })
          this.initSalType();
        }).catch(({ msg }) => {
          this.$loadingClose();
          this.$message({
            type: 'error',
            message: msg,
          });
        });
      },
      //单选工资类别改变
      handleTypeChange(v) {
        ff = [];
        this.typeCode = v;
        this.currentSalType = _.find(this.salTypeFilterData, function (o) {
          return o.typeCode == v;
        });
        this.currentSalTypeCode = v;
        //默认工资项为选中工资类别的第一个工资项
        if (this.salTypeItemFilterData.length > 0) {
          this.currentSalItemCode = this.salTypeItemFilterData[0].itemCode;
        }
        this.getTableData();//写上这个方法后,该方法可以使用这个单选工资类别改变的方法
      },
      handleItemChange(v, flag) {
        this.currentSalItemCode = v;
        this.getTableData();    //忘记了为什么要加这一个
      },
      initCellRender() {
        let vm = this;
        this.cellRender = function (instance,td,row,col,prop,value,cellProperties) {
          if ('numeric' == cellProperties.type) {
            vm.Handsontable.renderers.NumericRenderer.apply(this, arguments);
            if (value == 0) {
              td.innerHTML = '';
            }
          } else {
            vm.Handsontable.renderers.TextRenderer.apply(this, arguments);
          }
          td.style.color = '#000000';
          if (cellProperties.readOnly) {
          } else {
            td.style.backgroundColor = '#00FFFF';
          }
        };
      },
      handleCheckChange() {
        this.reLoadData();
      },

      //刷新的方法
      handleRefresh() {
        this.resetParam();
        this.getPageInfo();
      },
      handleExport(){
        let searchItemName = [];
        _.forEach(this.salTypeItemFilterData,o=>{
          if(o.itemCode == this.currentSalItemCode){
            searchItemName = o.itemName;
          }
        })
        let params = {
          agyCode: this.query.agy.madCode,
          fiscal: sal.getFiscal(this.query.agy.madCode, this.GET_LOGIN_INFO.fiscal),
          year: this.currentYear,
          typeCode: this.typeCode,
          mofDivCode: this.GET_LOGIN_INFO.mofDivCode,
          itemName: searchItemName,
          toMo: this.toMo,
          fromMo: this.currentMo,
        }
        let url =
          CONTEXT_PATH +
          '/sal/paydata/his/exportGrant?url=' +
          encodeURIComponent(JSON.stringify(params));
        download(url);
      },
      reLoadData() {
        if (this.hot) {
          this.hot.loadData(this.tableFilterData);
        }
      },
      handleSearchClear() {
        this.reLoadData();
      },
      destroyHots() {
        if (this.hot) {
          this.hot.destroy();
          this.hot = null;
        }
      },
      destroyTableData() {
        tableData = null;
      },
      handleYearChange() {
        this.resetParam();
        this.getSalTypeData();
      },
      resetParam() {
        this.currentSalType = {};
        this.currentSalTypeCode = null;
        this.currentMo = null;
        this.toMo= null;
      },
      initSalType() {
        if (this.salTypeData.length == 0) {
          this.resetParam();
          return;
        }
        //过滤启用的,及字段名转为驼峰
        _.forEach(this.salTypeData, function (o) {
          o.itemList = _.filter(o.itemList, function (item) {
            return item.isEnabled === 1;
          });
          _.forEach(o.itemList, function (item) {
            item.itemCode = tableview.toHump(item.itemCode);
          });
        });
        //月份下拉框
        if (this.currentMo == null && this.fromMoOptions.length > 0) {
          this.currentMo = this.fromMoOptions[0].value;
        }
        if(this.toMo == null && this.toMoOptions.length > 0){
          this.toMo = this.toMoOptions[0].value;
        }
        //设置默认值
        if (_.isEmpty(this.currentSalType)) {
          this.currentSalType = this.salTypeFilterData[0];
        } else {
          let v = this.currentSalType.typeCode;
          this.currentSalTypeCode = '';
          this.currentSalType = _.find(this.salTypeFilterData, function (o) {
            return o.typeCode == v;
          });
          if (!this.currentSalType) {
            this.currentSalType = this.salTypeFilterData[0];
          }
        }
        if (this.currentSalType) {
          this.currentSalTypeCode = this.currentSalType.typeCode;
        } else {
          this.currentSalTypeCode = null;
        }
        this.handleTypeChange(this.currentSalTypeCode);
      },
      tableFilterMoData() {
        //部门、搜索框、工资类别过滤。
        let checkNodes = this.$refs.tree2.getCheckedNodes(false, true); //部门
        // debugger
        let searchTextArray = [];
        let searchTextUpper = [];
        let tmp = _.split(_.trim(this.searchText), ' ');
        _.forEach(tmp, function (o) {
          if (_.trim(o) == '') {
            return;
          }
          searchTextArray.push(o); //push() 方法可向数组的末尾添加一个或多个元素,并返回新的长度。
          searchTextUpper.push(_.toUpper(o));
        });
        let searchTextFlag = searchTextArray.length > 0 ? true : false;
        let filterData = _.filter(tableData, (o) => {
          let b = o.salTypeCode === this.currentSalTypeCode;
          if (!b) {
            return false;
          }
          if (checkNodes.length > 0) {
            let f = _.find(checkNodes, function (s) {
              return s.madCode == o.departmentCode;
            });
            b = f ? true : false;
          }
          if (!b) {
            return false;
          }
          if (searchTextFlag) {
            for (let i = 0; i < searchTextArray.length; i++) {
              //人员代码,名称, 拼音简拼,大写
              if (
                o.empCode.indexOf(searchTextArray[i]) != -1 ||
                o.empName.indexOf(searchTextArray[i]) != -1
              ) {
                b = true;
                break;
              } else {
                b = false;
              }
            }
          }
          return b;
        });
        let cloneData = _.cloneDeep(filterData);
        let datas = [];
        _.forEach(cloneData, function (o) {
          let map = {};
          _.forEach(this.nestedHeaders, function (f) {
            let a = f.code;
            if (!map[f.code]) {
              map[f.code] = o[a];
            }
          });
          datas.push(map);
        });
        return datas;
      },
      //从工资项和公式表里面获取分好组的工资项作为动态表头   获取工资项数据
      getItemTabelData(){
        this.$loading();
        fetch.get('/sal/type/item/his/list', {
          params: {
            agyCode: sal.getAgyCode(this.query.agy.madCode),
            fiscal: sal.getFiscal(this.query.agy.madCode, this.GET_LOGIN_INFO.fiscal),
            typeCode: this.typeCode,
            year: this.currentYear,
            isEnabled: 1,
            mofDivCode: this.GET_LOGIN_INFO.mofDivCode,
          }
        }).then(({data}) => {
          this.$loadingClose();
          this.itemTableList =  _.filter(data,o =>{
            if(o.unitGrantCode != null){
              return data;
            }
          });
          _.forEach(this.itemTableList,h=>{
            if(_.indexOf(this.sTypeCode,h.typeCode)){
              this.sTypeCode.push(h.typeCode);
            }
          })
          this.getTableData();
        }).catch(({msg}) => {
          this.$loadingClose();
          this.$message({
            type: 'error',
            message:msg
          });
        });
      },
      buildMadDataMap() {
        //人员项值集构建代码名称map,基础数据取名称,不再构建。
        _.forEach(this.currentSchema.itemList, (o) => {
          if (o.getdataType === 1) {
            let f = _.find(this.getSchema().empFieldFilterData, function (field) {
              return field.fieldCode === o.calcExpression;
            });
            if (f) {
              if (util.isNotEmpty(f.atomCode)) {
                if (f.valsetCode == '1') {
                  if (!this.madDataMap[f.atomCode]) {
                    let codeMap = {};
                    let valsetList = getEnumerate(f.atomCode);
                    _.forEach(valsetList, (row) => {
                      codeMap[row.code] = row.name;
                    });
                    this.madDataMap[f.atomCode] = codeMap;
                  }
                } else if (f.valsetCode == '0') {
                  if (!this.madDataMap[f.atomCode]) {
                    let codeMap = {};
                    _.forEach(this.mad[f.atomCode], (row) => {
                      codeMap[row.code] = row.name;
                    });
                    this.madDataMap[f.atomCode] = codeMap;
                  }
                }
              }
            }
          }
        });
      },
      // 获取本年所有工资历史数据:
      getTableData() {
        this.$loading();
        let field = "card_id as cardId,max(emp_name) as empName,max(agy_code) as agyCode,max(emp_code) as empCode,max(department_name) as departmentName,max(department_code) as departmentCode,agy_name as agyName,mo as mo";
        let param = "card_id,emp_name,agy_name,mo,emp_code,agy_code,department_code,department_name";
        fetch.post('/sal/paydata/his/sumlist', {
          agyCode: sal.getAgyCode(this.query.agy.madCode),
          fiscal: sal.getFiscal(this.query.agy.madCode, this.GET_LOGIN_INFO.fiscal),
          mofDivCode: this.GET_LOGIN_INFO.mofDivCode,
          typeCode: this.currentSalTypeCode,
          year: this.currentYear,//年度下拉框不显示了,不清楚是不是这个地方的原因,也可能是缓存一下就好了
          fromMo: this.currentMo,
          toMo: this.toMo,
          field: field,
          param: param
        }).then(({data}) => {
          this.$loadingClose();
          tableData = data;
          let tables = [];
          tables.push(
            { name: '工资月份', data: 'mo', type: 'text', readOnly: true },
            { name: '单位编码', data: 'agyCode', type: 'text', readOnly: true },
            { name: '单位名称', data: 'agyName', type: 'text', readOnly: true },
            { name: '姓名', data: 'empName', type: 'text', readOnly: true },
            { name: '身份证号', data: 'cardId', type: 'text', readOnly: true },
            { name: '工资卡号', data: 'empBankAcc', type: 'text', readOnly: true },
            { name: '工资卡开户银行', data: 'accBankName', type:'text',readOnly: true},
          );
          this.getNestedHeaders();
          for(let aa of this.dongtaijiyibiaotou){
            for (let key of this.itemTableList){
              //key.typeCode === this.currentSalTypeCode控制页面上只显示当前工资类别的表头
              if(aa.label === key.unitGrantName && key.typeCode === this.currentSalTypeCode){
                tables.push(
                  {name: key.itemName,  data: key.itemCode, type:'numeric',readOnly: true}
                )
              }
            }
          }
          tables = _.uniqWith(tables, _.isEqual); //去重
          this.tableList = tables;
          this.initHandsontable();  //一开始没有在页面上显示就是因为没有加上这一步
        }).catch(({msg}) => {
          this.$loadingClose();
          this.$message({
            type: 'error',
            message: msg
          });
        });
      },
      isSystemPermission() {
        return sal.isSystemPermission(this.query.agy.madCode);
      },
    },
    computed:{
      ...mapGetters([GET_LOGIN_INFO, GET_CONTEXT_AGY_ACB]),
      tableHeight() {
        return this.innerHeight - 150;
      },
      fromMoOptions(){
        let that = this;
        let salTypeData = _.filter(this.salTypeData, (o) =>{
          return o.year == that.currentYear;
        });
        let moOptions = [];
        _.forEach(_.uniq(_.map(_.orderBy(salTypeData, ['mo'], ['desc']), 'mo')), (i) =>{
          moOptions.push({label: i + '月', value: i});
        });
        if(this.toMo != null){
          moOptions = _.filter(moOptions, (o) =>{
            return o.value <= that.toMo;
          });
        }
        return moOptions;
      },
      toMoOptions(){
        let that = this;
        let salTypeData = _.filter(this.salTypeData, (o) =>{
          return o.year == that.currentYear;
        });
        let moOptions = [];
        _.forEach(_.uniq(_.map(_.orderBy(salTypeData, ['mo'], ['desc']), 'mo')), (i) =>{
          moOptions.push({label: i + '月', value: i});
        });
        if(this.currentMo != null){
          moOptions = _.filter(moOptions, (o) =>{
            return o.value >= that.currentMo;
          });
        }
        return moOptions;
      },
      tableFilterData() {
        //部门、搜索框、工资类别过滤。
        let checkNodes = this.$refs.tree2.getCheckedNodes(false, true); //部门
        let filterData = tableview.filterTableData(tableData, checkNodes, this.currentSalTypeCode, this.searchText);
        return filterData;
      },
      //监听工资类别
      salTypeFilterData() {
        let filterSalType = [];
        let that = this;
        let map = {};
        _.forEach(this.salTypeData, (o) => {
          if (!map[o.typeCode]) {
            filterSalType.push(o);
            map[o.typeCode] = o;
          }
        });
        return filterSalType;
      },
      salTypeItemFilterData() {
        let filterSalItemCode = [];
        let that = this;
        let map = {};
        _.forEach(this.salTypeData, (o) => {
          if (
            util.isNotEmpty(this.currentSalTypeCode) &&
            this.currentSalTypeCode == o.typeCode
          ) {
            _.forEach(o.itemList, (i) => {
              if (i.dataType === 'number' && !map[i.itemCode]) {
                filterSalItemCode.push(i);
                map[i.itemCode] = i;
              }
            });
          }
        });
        return filterSalItemCode;
      },
    },
    mounted: function () {
      getMadInfo(this.query.agy.madCode).then((res = {}) => {
        this.$set(this.$data, 'mad', res);
      });
      this.init();
      $('.bar-line-left').hover(function (e) {
        if (!e) {
          e = window.event;
        }
        e.stopPropagation();
        $('.pfs-icon1').find('i').fadeToggle(300);
      });
    },
    beforeDestroy() {
      this.destroyHots();
      this.destroyTableData();
      this.deptPrintHots = null;
    },
    //系统页签切换后,handsontable表头没显示出来,此页签激活后重新渲染一下
    beforeRouteEnter(to, from, next) {
      let flag = hasView(to.path); //true打开过的
      next((vm) => {
        if (flag) {
          vm.reRenderHot();
        }
      });
    },
  };
</script>

<style lang="scss" scoped>
  @import '~@/assets/style/variables.scss';

  .dialog-form.new {
    width: 60%;
    margin-right: 20px;
    .el-form-item {
      padding-left: 30px;
    }
  }
  .dialog-box-card {
    width: 32%;
  }
  ::v-deep .el-card__header {
    padding: 10px 20px;
  }
  ::v-deep .el-tree {
    .heightLight {
      @include bs-color-primary;
    }
  }
  ::v-deep .el-date-editor.el-input, .el-date-editor.el-input__inner {
    width: 250px;
  }
  ::v-deep .search .el-input__inner {
    border: 1px solid #fff;
    border-radius: 0;
    //border-bottom: 1px solid #ddd;
    transition: 0s;
    padding-left: 3px;
    &:hover {
      //border: 1px solid rgba(82,168,236,0.8)!important;
      border-bottom: 1px solid rgba(82, 168, 236, 0.8) !important;
      //box-shadow: inset 0 1px 1px rgba(0,0,0,0.075), 0 0 8px rgba(82,168,236,0.6);
    }
    &:focus {
      //border: 1px solid rgba(82,168,236,0.8)!important;
      border-bottom: 1px solid rgba(82, 168, 236, 0.8) !important;
      //box-shadow: inset 0 1px 1px rgba(0,0,0,0.075), 0 0 8px rgba(82,168,236,0.6);
    }
  }
  .form-department {
    ::v-deep .el-form-item__label {
      color: red
    }
  }
  .bar-line-left {
    position: fixed;
    left: 0;
    top: 100px;
    z-index: 999;
    .pfs-line-border {
      display: inline-block;
      width: 10px;
      height: 30px;
      @include bs-background-color-primary;
      border-radius: 15px;
    }
  }
  #calcTable{
    overflow: inherit !important;
  }
  ::v-deep .hanson-table{
    .ht_master{
      overflow: inherit !important;
    }
  }
</style>

辅助页面

   <el-table-column prop="unitGrantCode" width="120" label="单位自发分类">
          <template slot-scope="scope">
            <el-select  size="mini" style="width: 100px" v-model="scope.row.unitGrantCode" @change="handleUnitChange(scope.row)" clearable>
              <el-option
                v-for="item in expecoAdd"
                :key="item.value"
                :label="item.label"
                :value="item.value">
              </el-option>
            </el-select>
            <span v-if="scope.row.unitGrantCode">
              {{scope.row.unitGrantCode}} {{scope.row.unitGrantName}}
            </span>
          </template>
        </el-table-column>
expecoAdd: [],
 //单位自发分类的点击事件,将页面上的值赋值给数据库中的字段
      handleUnitChange(row){
        _.forEach(this.expecoAdd,o=>{
          if(row.unitGrantCode == o.value){
            row.unitGrantName = o.label;
          }
        });
      },
mounted() {
      getMadInfo(this.query.agy.madCode).then((res = {}) => {
        let exAdd  = _.filter(res.EXPECO,o => {
          if(o.code === '30101' || o.code == '30102' || o.code == '30107' || o.code == '30199' || o.code == '30239' || o.code == '30309'){
            return o.code + o.name;
          }
        });
        this.expecoAdd = exAdd.map((item) => {
          return {
            label:item.name,
            value:item.code
          }
        })
      });
      this.initTableSort();
      this.getStandardData();
      this.getTableData();
    }

后端导出全部

 /**
     *  单位自发工资表导出excel 导出全部
     */
    public void exportGrant(HttpServletRequest request, Map<String, Object> params, HttpServletResponse response) {
        //获取参数
        String agyCode = params.get("agyCode").toString();
        Integer fiscal = Integer.parseInt(params.get("fiscal").toString());
        Integer year = Integer.parseInt(params.get("year").toString());
        Integer toMo = Integer.parseInt(params.get("toMo").toString());
        Integer currentMo = Integer.parseInt(params.get("fromMo").toString());
        //第一步,创建一个Workbook,对应一个Excel文件
        HSSFWorkbook wb = new HSSFWorkbook();

        //查询历史类别数据
        SalTypeHis salTypeHis = new SalTypeHis();
        salTypeHis.setAgyCode(agyCode);
        salTypeHis.setFiscal(fiscal);
        //需要获取到月份区间
        List<SalTypeHisVO> salTypeHisVOS = new ArrayList<>();//获取了历史工资项
        Map<String, SalTypeHisVO> typeMap = new HashMap<>();
        List<String> sheetNames = new ArrayList<>();
        for (SalTypeHisVO vo : salTypeHisService.selectVO(salTypeHis)) {
            if (vo.getMo() >= currentMo && vo.getMo() <= toMo) {
                if (typeMap.get(vo.getTypeCode()) == null) {
                    salTypeHisVOS.add(vo);
                    typeMap.put(vo.getTypeCode(), vo);
                    sheetNames.add(vo.getTypeName());
                }
            }
        }
        List<String> typeCodes = new ArrayList<>();
        for (SalTypeHisVO vo : salTypeHisVOS) {
            if (vo.getTaxType() != 3) {
                typeCodes.add(vo.getTypeCode());
            }
        }
        for(int x = 0;x<sheetNames.size();x++) {
            //第二步,在Workbook中添加一个sheet,对应Excel文件中的sheet
            HSSFSheet sheet = wb.createSheet(sheetNames.get(x));  //设置表格列宽度为10个字节
            sheet.setDefaultColumnWidth(15);
            //第三步,设置样式以及字体样式
            HSSFCellStyle headerStyle = createHeadCellStyle(wb);
            HSSFCellStyle contentStyle = createContentCellStyle(wb);//居右
            //需要获取到表格列数固定的是7  动态的表头长度需要 agyCode fiscal  typeCode为条件
            //从sal_type_item_his表中查询出来unitGrantCode不为空的数据
            SalTypeItem salTypeItemHis = new SalTypeItem();
            salTypeItemHis.setAgyCode(agyCode);
            salTypeItemHis.setFiscal(fiscal);
            salTypeItemHis.setYear(year);
            salTypeItemHis.setIsEnabled(1);
            salTypeItemHis.setTypeCode(typeCodes.get(x));
            Integer tableSize = 0;
            List<SalTypeItem> salTypeItemHisList = salTypeItemService.getList(salTypeItemHis);
            Integer tableL = 0;
            List<String> unitGrantNames = new ArrayList<>();
            List<String> finalOneHeader = new ArrayList<>();
            String[] row_second = {"工资月份", "单位编码", "单位名称", "姓名", "身份证号", "工资卡号", "工资卡开户银行"};
            for (int y = 0; y < row_second.length; y++) {
                finalOneHeader.add(row_second[y]);
                //将动态的一级表头放到数组表头中
                unitGrantNames.add(row_second[y]);
            }
            Map<String, String> inUnitGrantNames = new HashMap<>();
            for (int j = 0; j < salTypeItemHisList.size(); j++) {
                if (salTypeItemHisList.get(j).getUnitGrantCode() != null) {
                    //获取到当前工资类别中二级表头中一级表头的个数和名称,需要对一级表头进行去重
                    if (salTypeItemHisList.get(j).getUnitGrantName() != null && !unitGrantNames.contains(salTypeItemHisList.get(j).getUnitGrantName())) {
                        unitGrantNames.add(salTypeItemHisList.get(j).getUnitGrantName());
                    }
                    //key为二级表头,value为一级表头
                    inUnitGrantNames.put(salTypeItemHisList.get(j).getItemName(), salTypeItemHisList.get(j).getUnitGrantName());
                    tableL++;
                }
            }
            //获取相同的一级表头下,二级表头的个数  结果 (测试  2  非测试  3)
            Map<String, Integer> finalInNames = new HashMap<>();
            for (Map.Entry<String, String> entry : inUnitGrantNames.entrySet()) {
                if (finalInNames.containsKey(entry.getValue())) {
                    finalInNames.put(entry.getValue(), finalInNames.get(entry.getValue()) + 1);
                } else {
                    finalInNames.put(entry.getValue(), 1);
                }
            }
            tableSize = tableL + 7;  //获取到表格的长度
            //查询出当前页面的所有数据
            SalPayDataHis salPayDataHis = new SalPayDataHis();
            salPayDataHis.setAgyCode(agyCode);
            salPayDataHis.setFiscal(fiscal);
            salPayDataHis.setSalTypeCode(typeCodes.get(x));
            List<SalPayDataHis> salPayDataList = new ArrayList<>();
            for (SalPayDataHis newSalPayDataHis : salPayDataHisService.list(salPayDataHis)) {
                if (newSalPayDataHis.getMo() >= currentMo && newSalPayDataHis.getMo() <= toMo) {
                    salPayDataList.add(newSalPayDataHis);
                }
            }


            //第四步,创建标题 ,合并标题单元格
            // 行号
            int rowNum = 0;
            //第一行
            HSSFRow row2 = sheet.createRow(rowNum++);

            List<String> newYiName = new ArrayList<>();
            for (int q = 7; q < unitGrantNames.size(); q++) {
                newYiName.add(unitGrantNames.get(q));
            }
            // 合并
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 0, 0));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 1, 1));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 2, 2));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 3, 3));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 4, 4));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 5, 5));
            sheet.addMergedRegion(new CellRangeAddress(0, 1, 6, 6));
            Integer firstNum = 6;
            Integer lastNum = 6;
            //给动态的一级表头合并单元格
            for (int w = 0; w < newYiName.size(); w++) {
                for (String num : finalInNames.keySet()) {
                    if (newYiName.get(w).equals(num)) {
                        if (w == 0) {
                            firstNum = firstNum + 1;
                        } else {
                            firstNum = lastNum + 1;
                        }
                        //需要和表头对应
                        lastNum = finalInNames.get(num) + lastNum;
                        Integer cal = lastNum - firstNum;
                        finalOneHeader.add(num);
                        //避免其他单元格被占据多列单元格的覆盖
                        if (cal != 0) {
                            for (int v = 0; v < cal; v++) {
                                finalOneHeader.add(" ");
                            }
                        }
                        if (firstNum != lastNum) {
                            sheet.addMergedRegion(new CellRangeAddress(0, 0, firstNum, lastNum));
                        }
                        break;
                    }
                }
            }
            for (int k = 0; k < finalOneHeader.size(); k++) {
                //创建一个单元格
                HSSFCell cell = row2.createCell(k);
                //创建一个内容对象
                HSSFRichTextString text = new HSSFRichTextString(finalOneHeader.get(k));
                //将内容对象的文字内容写入到单元格中
                cell.setCellValue(text);
                cell.setCellStyle(headerStyle);
            }
            //第三行
            HSSFRow row3 = sheet.createRow(1);
            String[] row_third = {"", "", "", "", "", "", ""};
            List<String> newErHead = new ArrayList<>();
            for (int b = 0; b < row_third.length; b++) {
                newErHead.add(row_third[b]);
            }
            for (int s = 7; s < unitGrantNames.size(); s++) {
                for (String key : inUnitGrantNames.keySet()) {
                    if (unitGrantNames.get(s).equals(inUnitGrantNames.get(key))) {
                        newErHead.add(key);
                    }
                }
            }
            for (int g = 0; g < newErHead.size(); g++) {
                //创建一个单元格
                HSSFCell cell = row3.createCell(g);
                //创建一个内容对象
                HSSFRichTextString text = new HSSFRichTextString(newErHead.get(g));
                //将内容对象的文字内容写入到单元格中
                cell.setCellValue(text);
                cell.setCellStyle(headerStyle);
            }
            //获取到工资项名称,匹配到工资项编码,然后进行工资项的动态数据绑定
            //查询授权工资项
            List<String> newErCode = new ArrayList<>();
            for (int l = 7; l < newErHead.size(); l++) {
                for (int r = 0; r < salTypeItemHisList.size(); r++) {
                    if (newErHead.get(l).equals(salTypeItemHisList.get(r).getItemName())) {
                        newErCode.add(salTypeItemHisList.get(r).getItemCode());
                        break;
                    }
                }
            }
            //绑定数据
            for (int t = 0; t < salPayDataList.size(); t++) {
                //创建一行
                HSSFRow row4 = sheet.createRow(t + 2);
                row4.setRowStyle(contentStyle);
                row4.createCell(0).setCellValue(salPayDataList.get(t).getMo());
                row4.createCell(1).setCellValue(salPayDataList.get(t).getAgyCode());
                row4.createCell(2).setCellValue(salPayDataList.get(t).getAgyName());
                row4.createCell(3).setCellValue(salPayDataList.get(t).getEmpName());
                row4.createCell(4).setCellValue(salPayDataList.get(t).getCardId());
                row4.createCell(5).setCellValue(salPayDataList.get(t).getBankAcc());
                row4.createCell(6).setCellValue(salPayDataList.get(t).getEmpBankAcc());
                //获取到工资项名称,匹配到工资项编码,然后进行工资项的动态数据绑定
                for (int p = 0; p < newErCode.size(); p++) {
                    BigDecimal data = getProperty(salPayDataList.get(t), newErCode.get(p));
                    if (p == 0) {
                        row4.createCell(7).setCellValue(data.toString());
                    } else {
                        row4.createCell(7 + p).setCellValue(data.toString());
                    }
                }
            }
        }
            try {
                //准备将Excel的输出流通过response输出到页面下载
                //八进制输出流
                response.setContentType("application/octet-stream");
                response.setCharacterEncoding("utf-8");
                //这后面可以设置导出Excel的名称,此例中名为student.xls(解决文件名称乱码问题)
                response.setHeader("content-disposition", "attachment;filename=" + new String("工资项汇总表".getBytes(), "ISO8859-1") + ".xlsx" );
                //刷新缓冲
                response.flushBuffer();
                //workbook将Excel写入到response的输出流中,供页面下载
                wb.write(response.getOutputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    /*
     *通过属性名获取到属性值
     * */
    public static BigDecimal getProperty(SalPayDataHis salPayDataHis, String value) {
        BigDecimal bigDecimal = new BigDecimal(BigInteger.ZERO);
        try{
            // 获取Bean的某个属性的描述符
            PropertyDescriptor proDescriptor = new PropertyDescriptor(value, SalPayDataHis.class);
            // 获得用于读取属性值的方法
            Method readMethod = proDescriptor.getReadMethod();
            // 读取属性值
            bigDecimal = (BigDecimal)readMethod.invoke(salPayDataHis);
        }catch (Exception e){
            e.printStackTrace();
        }
        return bigDecimal;
    }

    /**
     * 创建内容样式
     *
     * @param wb
     * @return
     */
    private static HSSFCellStyle createContentCellStyle1(HSSFWorkbook wb) {
        HSSFCellStyle cellStyle = wb.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中
        cellStyle.setAlignment(HorizontalAlignment.LEFT);// 水平居左
        cellStyle.setWrapText(true);// 设置自动换行
        cellStyle.setBorderBottom(BorderStyle.THIN); //下边框
        cellStyle.setBorderLeft(BorderStyle.THIN); //左边框
        cellStyle.setBorderRight(BorderStyle.THIN); //右边框
        cellStyle.setBorderTop(BorderStyle.THIN); //上边框

        // 生成12号字体
        HSSFFont font = wb.createFont();
        font.setColor((short) 8);
        font.setFontHeightInPoints((short) 12);
        cellStyle.setFont(font);

        return cellStyle;
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值