Skip to content

表格组件行单选、多选公共方法

公共方法路径:mixin/page.js

javascript
import Vue from 'vue';

/**
 * 选择行数据
 * 1、如果当前行数据已被选中,则从选中的数据中删除
 * 2、如果当前行数据未被选中,则需要选中,并设置相关字段数据
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} rowData 行数据 {field1: '', field2: ''}
 * @param {*} field 行数据唯一性key字段
 * @param {*} setValue 设置值的函数 (rowData) => ({field1: '', field2: ''});
 */
export function selectRow(select, rowData, field, setValue) {
  if (rowData[field] in select) {
    Vue.delete(select, rowData[field]);
  } else {
    Vue.set(select, rowData[field], setValue(rowData));
  }
}

/**
 * 选择全部行数据
 * @param {*} vmData vue data 实例
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} allData [{field1: '', field2: ''}, {field1: '', field2: ''}]
 * @param {*} field 行数据唯一性key字段
 * @param {*} setValue 设置值的函数 (rowData) => ({field1: '', field2: ''});
 */
export function selectAllRow(vmData, select, allData, field, setValue) {
  select = { ...select };
  allData.forEach((e) => {
    if (!(e[field] in select)) {
      select[e[field]] = setValue(e);
    }
  });
  Vue.set(vmData, 'select', select);
}

/**
 * 取消选择的行数据
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} key 行数据唯一性key字段
 */
export function deselectRow(select, key) {
  Vue.delete(select, key);
}

/**
 * 取消选择部分行数据
 * @param {*} select 页面已选数据
 * @param {*} dataFilter 页面显示数据
 * @param {*} field 行数据唯一性字段
 */
export function deselectSelectRow(select, dataFilter, field) {
  dataFilter.forEach(rowData => {
    Vue.delete(select, rowData[field]);
  });
}

/**
 * 取消选择全部行数据
 * @param {*} vmData vue data 实例
 */
export function deselectAllRow(vmData) {
  Vue.set(vmData, 'select', {});
}

/**
 * 已选行数据条数
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @returns
 */
export function selectRowLength(select) {
  return Object.keys(select).length;
}

/**
 * 是否选中了当前行数据
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} key 行数据唯一性key字段
 * @returns
 */
export function isSelectRow(select, key) {
  return key in select;
}

/**
 * 是否选中了全部行数据
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} dataFilter  页面显示行数据 [{field1: '', field2: ''}, {field1: '', field2: ''}]
 * @param {*} field 行数据唯一性字段
 */
export function isSelectAllRow(select, dataFilter, field) {
  let selectLen = selectRowLength(select);
  return selectLen !== 0 && dataFilter.every(e => {
    return e[field] in select;
  });
}

/**
 * 过滤选中的行数据
 * @param {*} select 已选中的行数据 {key1: {field1: '', field2: ''}, key1: {field1: '', field2: ''}}
 * @param {*} filterFunc  过滤的函数
 * @returns
 */
export function filterSelectRow(select, filterFunc) {
  let result = [];
  for (let e in select) {
    if (filterFunc(select[e])) {
      result.push(select[e]);
    }
  }
  return result;
}

表格不分页单选多选示例

使用示例

image1.png

代码示例

代码中所有加TODO的地方需要注意

  • mixin/page文件中引入单选多选相关公共方法
  • 第一列为选择列
  • 头部插槽是表格全选,value属性绑定isSelectAllRow计算属性,响应change事件触发onSelectAllRow方法
  • 单元格插槽是行单选,value属性绑定isSelectRow方法,响应change事件,触发onSelectRow方法
  • 增加已选的行数据对象
  • 底部展示当前选择的行数据信息
  • 更新表格数据时,需要取消选择全部行数据
  • 调用公共方法处理行选择
  • 调用公共方法处理全选
  • 设置选中行数据需要根据实际业务设置具体的字端
  • 调用公共方法处理取消行选择
  • 批量按钮操作时,过滤出有效的行数据
  • 批量按钮操作完毕时,应该取消选择全部行数据
  • 调用公共方法判断是否选择当前行数据
  • 调用公共方法获取当前已选择的行数据条数
  • 调用公共方法判断是否选中了全部行数据
vue
<!-- 下级报表管理审核-内容区域-数据一致性检查-按单位 -->
<template>
  <!-- 容器 -->
  <div class="pfs-gfa-audit-manage-content-acc-check-agency">
    <!-- 表格区域 -->
    <vxe-table ref="xTable" :data="dataFilter" size="mini" resizable border round :height="tableHeight" row-class-name="poi" :header-cell-style="TABLE_HEADER_CELL_STYLE" :cell-style="TABLE_CELL_STYLE" highlight-current-row :scroll-y="{enabled: true}" auto-resize :show-overflow="true">
      <!-- TODO:第一列为选择列 -->
      <vxe-table-column header-align="center" align="center" width="50">
        <!-- TODO:头部插槽是表格全选,value属性绑定isSelectAllRow计算属性,响应change事件触发onSelectAllRow方法 -->
        <template v-slot:header>
          <v-checkbox :value="isSelectAllRow" :true-label="true" :false-label="false" @change="onSelectAllRow" />
        </template>
        <!-- TODO:单元格插槽是行单选,value属性绑定isSelectRow方法,响应change事件,触发onSelectRow方法 -->
        <template v-slot:default="scope">
          <v-checkbox :value="isSelectRow(scope.row.id)" :true-label="true" :false-label="false" @change="onSelectRow(scope.row)" />
        </template>
      </vxe-table-column>
      <vxe-table-column field="reportCode" title="报表标识" width="120" header-align="center" align="left">
        <template v-slot:header="scope">
          <div class="flex-center">
            <span>{{scope.column.title}}</span>
            <!-- 列过滤组件 -->
            <v-column-filter :is-active="hasColumnFilter('reportCode')" :getData="() => getColumnData('reportCode')" :getChecked="() => getColumnFilterData('reportCode')" @change="onColumnFilterChange('reportCode', $event)" />
          </div>
        </template>
      </vxe-table-column>
      <vxe-table-column field="reportName" title="报表名称" header-align="center" align="left" width="200">
        <template v-slot:header="scope">
          <div class="flex-center">
            <span>{{scope.column.title}}</span>
            <!-- 列过滤组件 -->
            <v-column-filter :is-active="hasColumnFilter('reportName')" :getData="() => getColumnData('reportName')" :getChecked="() => getColumnFilterData('reportName')" @change="onColumnFilterChange('reportName', $event)" />
          </div>
        </template>
      </vxe-table-column>
      <vxe-table-column field="expFuncName" title="支出功能分类" header-align="center" align="left" width="200">
        <template v-slot:default="scope">
          {{scope.row.expFuncCode}} {{scope.row.expFuncName}}
        </template>
      </vxe-table-column>
      <vxe-table-column field="reportItemName" title="报表项目" header-align="center" align="left" width="170"></vxe-table-column>
      <vxe-table-column field="reportAmt" title="报表金额" header-align="center" align="right" width="150">
        <template v-slot="{row}">{{row.reportAmt | formatCurrency }}</template>
      </vxe-table-column>
      <vxe-table-column field="subject" title="取数科目" header-align="center"  align="left" width="200"></vxe-table-column>
      <vxe-table-column field="accountAmt" title="账套金额" header-align="center" align="right" width="150">
        <template v-slot="{row}">{{row.accountAmt | formatCurrency }}</template>
      </vxe-table-column>
      <vxe-table-column field="imbalanceAmt" title="差额" header-align="center" align="right" width="150">
        <template v-slot="{row}">{{row.imbalanceAmt | formatCurrency }}</template>
      </vxe-table-column>
      <vxe-table-column field="accountCause" title="差异说明" header-align="center" align="left" width="200"></vxe-table-column>
      <vxe-table-column field="passCause" title="上级意见" width="200" header-align="center" align="left"></vxe-table-column>
      <vxe-table-column field="accountStatus" title="审核状态" width="120" header-align="center" align="center" fixed="right">
        <template v-slot:default="scope">
          {{accountStatusDisplay(scope.row)}}
        </template>
      </vxe-table-column>
      <vxe-table-column title="操作" width="130" header-align="center" align="center" fixed="right">
        <template v-slot:default="scope">
          <el-button type="text" :disabled="!canPass(scope.row)" @click="onAudit(AUDIT_TYPE.PASS, scope.row)" style="padding: 0;">通过</el-button>
          <el-divider direction="vertical"></el-divider>
          <el-button type="text" :disabled="!canReturn(scope.row)" @click="onAudit(AUDIT_TYPE.NO_PASS, scope.row)" style="padding: 0;">不通过</el-button>
        </template>
      </vxe-table-column>
    </vxe-table>
    <!-- 底部操作栏 -->
    <div class="pfs-gfa-audit-manage-content-acc-check-agency-bottom">
      <el-button size="mini" :disabled="!agencyCanAudit" @click="onBatchAudit(AUDIT_TYPE.PASS)">
        <v-svg type="bs-enable" :disabled="!agencyCanAudit"></v-svg> 通过
      </el-button>
      <el-button size="mini" :disabled="!agencyCanAudit" @click="onBatchAudit(AUDIT_TYPE.NO_PASS)">
        <v-svg type="bs-fail" :disabled="!agencyCanAudit"></v-svg> 不通过
      </el-button>
      <!-- TODO:底部展示当前选择的行数据信息 -->
      <template v-if="selectRowLength > 0">
        <el-divider direction="vertical"></el-divider>
        <span class="ml5 b">已勾选:</span>
        <el-popover ref="popover" v-model="popoverVisible" placement="bottom-start" trigger="hover" width="350">
          <div class="pfs-gfa-audit-manage-content-acc-check-agency-selection" v-if="popoverVisible">
            <div class="pfs-gfa-audit-manage-content-acc-check-agency-option" :key="k" v-for="(e, k) in select">
              <div class="bs-color-primary f14 ell" :title="e.value">{{e.value}}</div>
              <div class="pfs-gfa-audit-manage-content-acc-check-agency-option-remove" @click="onDeselectRow(k)">
                <i class="fa fa-times-circle-o bs-color-red poi"></i>
              </div>
            </div>
          </div>
          <span class="bs-link-primary" slot="reference">{{selectRowLength}} 笔</span>
        </el-popover>
      </template>
    </div>
  </div>
</template>
<script>
import fetch from '@/config/fetch';
import util from '@/assets/js/util';
// TODO:mixin/page文件中引入单选多选相关公共方法
import { selectRow, selectAllRow, deselectRow, deselectSelectRow, deselectAllRow, selectRowLength, isSelectRow, isSelectAllRow, filterSelectRow, TABLE_HEADER_CELL_STYLE, TABLE_CELL_STYLE,  } from '@/mixin/page';
import { AUDIT_TYPE, AUDIT_STATUS, AUDITED_STATUS } from '@/modules/pfs/pfs-gfa/pfs-gfa-audit-manage/constant';
import { auditStatus, canPass, canReturn, getColumnData, getColumnFilterData, onColumnFilterChange, hasColumnFilter, dataColumnFilter, resetColumnFilter, publishAuditedStatusChange } from '@/modules/pfs/pfs-gfa/pfs-gfa-audit-manage/service';

export default {
  props: {
    contextInfo: Object, //上下文数据
    agencyInfo: Object, //当前选的单位信息
    agencyCanAudit: Boolean, //当前单位数据是否可以进行审核
    audit: Function, //单位审核方法
  },
  data() {
    return {
      data: [], //表格数据
      columnFilter: {
        reportCode: [], //报表标识
        reportName: [], //报表名称
      }, //列过滤相关的过滤值
      tableHeight: 0, //表格高度
      select: {}, //已选的行数据  TODO:增加已选的行数据对象
      popoverVisible: false,  //已勾选弹框是否显示
      TABLE_HEADER_CELL_STYLE,
      TABLE_CELL_STYLE,
      AUDIT_TYPE,
    };
  },
  methods: {
    /**
     * 获取表格数据
     * 1、获取数据
     * 2、设置数据
     */
    async getData() {
      try {
        this.$loading();
        let { data } = await fetch.post('/gfa/fr/gfa/rpt/checkout/analyzeData', this.buildParams());
        this.setData(data);
      } catch (err) {
        console.error(err);
        this.$message({
          type: 'error',
          message: err.msg,
        });
      } finally {
        this.$loadingClose();
      }
    },
    /**
     * 设置数据
     * 1、设置数据时,需要做数据精简
     */
    setData(data) {
      data = data || [];
      data = data.map((e) =>
        _.pick(e, [
          'id',
          'reportCode',
          'reportName',
          'expFuncCode',
          'expFuncName',
          'reportItemName',
          'reportAmt',
          'subject',
          'accountAmt',
          'imbalanceAmt',
          'accountCause',
          'passCause',
          'accountStatus',
        ])
      );
      this.data = data;
    },
    /**
     * 更新数据
     * 1、清空状态数据
     * 2、页面完成渲染之后,重新获取表格数据
     */
    updateData() {
      this.data = [];
      resetColumnFilter(this.$data);
      // TODO:更新表格数据时,需要取消选择全部行数据
      deselectAllRow(this.$data);
      this.$nextTick(() => {
        this.getData();
      });
    },
    /**
     * 设置表格高度
     */
    setTableHeight() {
      this.tableHeight = $('.pfs-gfa-audit-manage-content-acc-check-agency').height() - 35;
    },
    /**
     * 获取当前列过滤选项数据
     */
    getColumnData(field) {
      return getColumnData(this.data, this.dataFilter, this.columnFilter, field);
    },
    /**
     * 获取列过滤相关的字段过滤值
     */
    getColumnFilterData(field) {
      return getColumnFilterData(this.columnFilter, field);
    },
    /**
     * 构建请求参数
     */
    buildParams() {
      let { transType, taskId, fiscalYear } = this.contextInfo;
      let { agencyCode, mofDivCode } = this.agencyInfo;
      return {
        mofDivCode,
        transType,
        taskId,
        setYear: fiscalYear,
        dwCode: agencyCode,
      };
    },
    /**
     * 设置选中行的数据
     */
    setSelectValue(rowData) {
      // TODO:设置选中行数据需要根据实际业务设置具体的字端
      return {
        id: rowData.id,
        accountStatus: rowData.accountStatus,
        value: `${rowData.reportName}--${rowData.expFuncCode}`,
      };
    },
    /**
     * 设置列过滤相关的过滤值
     */
    onColumnFilterChange(field, value) {
      onColumnFilterChange(this.columnFilter, field, value);
    },
    /**
     * 处理行选择
     */
    onSelectRow(rowData) {
      // TODO:调用公共方法处理行选择
      selectRow(this.select, rowData, 'id', this.setSelectValue);
    },
    /**
     * 处理全选
     */
    onSelectAllRow() {
      // TODO:调用公共方法处理全选
      if (!this.isSelectAllRow) {
        selectAllRow(this.$data, this.select, this.dataFilter, 'id', this.setSelectValue);
      } else {
        deselectSelectRow(this.select, this.dataFilter, 'id');
      }
    },
    /**
     * 处理取消行选择
     */
    onDeselectRow(key) {
      // TODO:调用公共方法处理取消行选择
      deselectRow(this.select, key);
    },
    /**
     * 处理审核
     * 1、调用审核接口进行审核
     * 2、更改当前单位审核状态
     * 3、若为不通过操作,发布单位完成审核状态
     */
    async onAudit(auditType, rowData) {
      try {
        this.$loading();
        let passCause = await this.audit(auditType, [rowData.id]);
        rowData.accountStatus = auditType === AUDIT_TYPE.PASS ? AUDIT_STATUS.PASS : AUDIT_STATUS.NO_PASS;
        if (auditType === AUDIT_TYPE.NO_PASS) {
          rowData.passCause = passCause;
        }
        this.$message({
          type: 'success',
          message: '审核成功!',
        });
        if (auditType === AUDIT_TYPE.NO_PASS) {
          publishAuditedStatusChange(AUDITED_STATUS.UN_FINISHED, [this.agencyInfo.agencyCode]);
        }
      } catch (err) {
        console.error(err);
        this.$message({
          type: 'error',
          message: err.msg,
        });
      } finally {
        this.$loadingClose();
      }
    },
    /**
     * 处理批量审核
     * 1、过滤出已选的数据里面有效的数据
     * 2、执行审核
     * 3、更新表格数据
     * 4、重置复选的行数据
     * 5、若为不通过操作,发布单位完成审核状态
     */
    async onBatchAudit(auditType) {
      try {
        this.$loading();
        let filterFunc = auditType === AUDIT_TYPE.PASS ? this.canPass : this.canReturn;
        // TODO:批量按钮操作时,过滤出有效的行数据
        let effectiveData = filterSelectRow(this.select, filterFunc);
        if (util.isEmpty(effectiveData)) {
          this.$message({
            type: 'warning',
            message: '未选择有效的数据!',
          });
          return;
        }
        effectiveData = effectiveData.map((e) => e.id);
        let passCause = await this.audit(auditType, effectiveData);
        let accountStatus = auditType === AUDIT_TYPE.PASS ? AUDIT_STATUS.PASS : AUDIT_STATUS.NO_PASS;
        this.data.forEach((e) => {
          if (effectiveData.includes(e.id)) {
            e.accountStatus = accountStatus;
            if (auditType === AUDIT_TYPE.NO_PASS) {
              e.passCause = passCause;
            }
          }
        });
        // TODO:批量按钮操作完毕时,应该取消选择全部行数据
        deselectAllRow(this.$data);
        this.$message({
          type: 'success',
          message: `审核成功,共处理 ${effectiveData.length} 条数据!`,
        });
        if (auditType === AUDIT_TYPE.NO_PASS) {
          publishAuditedStatusChange(AUDITED_STATUS.UN_FINISHED, [this.agencyInfo.agencyCode]);
        }
      } catch (err) {
        console.error(err);
        this.$message({
          type: 'error',
          message: err.msg,
        });
      } finally {
        this.$loadingClose();
      }
    },
    /**
     * 列过滤状态
     */
    hasColumnFilter(field) {
      return hasColumnFilter(this.columnFilter, field);
    },
    /**
     * 审核状态显示
     */
    accountStatusDisplay(rowData) {
      return auditStatus(rowData.accountStatus);
    },
    /**
     * 是否可以通过
     */
    canPass(rowData) {
      return canPass(this.agencyInfo.status, rowData.accountStatus);
    },
    /**
     * 是否可以退回
     */
    canReturn(rowData) {
      return canReturn(this.agencyInfo.status, rowData.accountStatus);
    },
    /**
     * 是否选择当前行数据
     */
    isSelectRow(key) {
      //TODO:调用公共方法判断是否选择当前行数据
      return isSelectRow(this.select, key);
    },
  },
  computed: {
    /**
     * 表格数据过滤
     */
    dataFilter() {
      return dataColumnFilter(this.data, this.columnFilter);
    },
    /**
     * 已选行数据条数
     */
    selectRowLength() {
      // TODO:调用公共方法获取当前已选择的行数据条数
      return selectRowLength(this.select);
    },
    /**
     * 是否选中了全部行数据
     */
    isSelectAllRow() {
      // TODO:调用公共方法判断是否选中了全部行数据
      return isSelectAllRow(this.select, this.dataFilter, 'id');
    },
  },
  mounted() {
    this.getData();
    this.setTableHeight();
  }
};
</script>
<style lang="scss" scoped>
@import '~@/assets/style/variables.scss';
.pfs-gfa-audit-manage-content-acc-check-agency {
  height: 100%;
  .pfs-gfa-audit-manage-content-acc-check-agency-bottom {
    height: 35px;
    margin-top: 5px;
    display: flex;
    align-items: center;
  }
}
// TODO:当前已选行数据信息展示的css样式
.pfs-gfa-audit-manage-content-acc-check-agency-selection {
  padding: 6px 0;
  overflow-y: auto;
  overflow-x: hidden;
  box-sizing: border-box;
  max-height: 300px;
  .pfs-gfa-audit-manage-content-acc-check-agency-option {
    position: relative;
    padding: 0 40px 0 10px;
    height: 28px;
    line-height: 28px;
    &:hover {
      background-color: $-bs-bg-color;
    }
    .pfs-gfa-audit-manage-content-acc-check-agency-option-remove {
      position: absolute;
      top: 0;
      right: 5px;
      font-size: 1.2em;
    }
  }
}
</style>

表格分页单选多选示例

使用示例

image2.png

代码示例

代码中所有加TODO的地方需要注意

  • 第一列为选择列
  • 单元格插槽是行单选,value属性绑定isSelectRow方法,响应change事件,触发onSelectRow方法
  • 底部展示当前选择的行数据信息,及全选操作
  • mixin/page文件中引入单选多选相关公共方法
  • 增加已选的行数据对象
  • 更新表格数据时,需要取消选择全部行数据,一般用于表格初始化操作
  • 设置选中行数据需要根据实际业务设置具体的字端
  • 调用公共方法处理行选择
  • 调用公共方法处理全选
  • 调用公共方法处理取消全选
  • 调用公共方法处理取消行选择
  • 批量按钮操作时,过滤出有效的行数据
  • 批量按钮操作完毕时,应该取消选择全部行数据
  • 调用公共方法判断是否选择当前行数据
  • 调用公共方法获取当前已选择的行数据条数
vue
<!-- 下级报表管理审核-内容区域-数据一致性检查-按类别 -->
<template>
  <!-- 容器 -->
  <div class="pfs-gfa-audit-manage-content-acc-check-category">
    <span>报送主体:</span>
    <v-tree-input v-model="query.agencyCodeList" :data="agencyList" :expand="false" :props="agencyProps" placeholder="选择报送主体" clearable />
    <span class="ml20">报表:</span>
    <v-tree-input :data="reportList" :expand="false" :multiple="false" :props="reportProps" sort-key="dispOrder" placeholder="选择报表" clearable @change="onReportChange" />
    <el-button size="small" style="margin-left: 20px;" @click="getPageInfo">
      <v-svg type="bs-search"></v-svg> 查询
    </el-button>
    <!-- 表格区域 -->
    <div class="mt5">
      <vxe-table ref="xTable" :data="tableData" size="mini" resizable border round :height="tableHeight" row-class-name="poi" :header-cell-style="TABLE_HEADER_CELL_STYLE" :cell-style="TABLE_CELL_STYLE" highlight-current-row :scroll-y="{enabled: true}" auto-resize :show-overflow="true">
        <!-- TODO:第一列为选择列 -->
        <vxe-table-column header-align="center" align="center" width="50">
          <!-- TODO:单元格插槽是行单选,value属性绑定isSelectRow方法,响应change事件,触发onSelectRow方法 -->
          <template v-slot:default="scope">
            <v-checkbox :value="isSelectRow(scope.row.id)" :true-label="true" :false-label="false" @change="onSelectRow(scope.row)"/>
          </template>
        </vxe-table-column>
        <vxe-table-column field="dwCode" title="报送主体编码" width="160" header-align="center" align="left"></vxe-table-column>
        <vxe-table-column field="dwName" title="报送主体名称" width="200" header-align="center" align="left"></vxe-table-column>
        <vxe-table-column field="reportName" title="报表" header-align="center" align="left" width="200">
          <template v-slot:default="scope">
            {{scope.row.reportCode}} {{scope.row.reportName}}
          </template>
        </vxe-table-column>
        <vxe-table-column field="expFuncName" title="支出功能分类" header-align="center" align="left" width="200">
          <template v-slot:default="scope">
            {{scope.row.expFuncCode}} {{scope.row.expFuncName}}
          </template>
        </vxe-table-column>
        <vxe-table-column field="reportItemName" title="报表项目" header-align="center" align="left" width="170"></vxe-table-column>
        <vxe-table-column field="reportAmt" title="报表金额" header-align="center" align="right" width="150">
          <template v-slot="{row}">{{row.reportAmt | formatCurrency }}</template>
        </vxe-table-column>
        <vxe-table-column field="subject" title="取数科目" header-align="center" align="left" width="200"></vxe-table-column>
        <vxe-table-column field="accountAmt" title="账套金额" header-align="center" align="right" width="150">
          <template v-slot="{row}">{{row.accountAmt | formatCurrency }}</template>
        </vxe-table-column>
        <vxe-table-column field="imbalanceAmt" title="差额" header-align="center" align="right" width="150">
          <template v-slot="{row}">{{row.imbalanceAmt | formatCurrency }}</template>
        </vxe-table-column>
        <vxe-table-column field="accountCause" title="差异说明" header-align="center" align="left" width="200"></vxe-table-column>
        <vxe-table-column field="passCause" title="上级意见" width="200" header-align="center" align="left"></vxe-table-column>
        <vxe-table-column field="accountStatus" title="审核状态" width="120" header-align="center" align="center" fixed="right">
          <template v-slot:default="scope">
            {{accountStatusDisplay(scope.row)}}
          </template>
        </vxe-table-column>
        <vxe-table-column title="操作" width="130" header-align="center" align="center" fixed="right">
          <template v-slot:default="scope">
            <el-button type="text" :disabled="!canPass(scope.row)" @click="onAudit(AUDIT_TYPE.PASS, scope.row)" style="padding: 0;">通过</el-button>
            <el-divider direction="vertical"></el-divider>
            <el-button type="text" :disabled="!canReturn(scope.row)" @click="onAudit(AUDIT_TYPE.NO_PASS, scope.row)" style="padding: 0;">不通过</el-button>
          </template>
        </vxe-table-column>
      </vxe-table>
    </div>
    <!-- 底部区域 -->
    <div class="pfs-gfa-audit-manage-content-acc-check-category-bottom">
      <!-- 左侧操作按钮 -->
      <div>
        <el-button size="mini" @click="onBatchAudit(AUDIT_TYPE.PASS)">
          <v-svg type="bs-enable"></v-svg> 通过
        </el-button>
        <el-button size="mini" @click="onBatchAudit(AUDIT_TYPE.NO_PASS)">
          <v-svg type="bs-fail"></v-svg> 不通过
        </el-button>
        <el-divider direction="vertical"></el-divider>
        <!-- TODO:底部展示当前选择的行数据信息,及全选操作 -->
        <el-button type="text" size="mini" @click="onSelectAllRow">全选</el-button>
        <template v-if="selectRowLength > 0">
          <el-divider direction="vertical"></el-divider>
          <el-button type="text" size="mini" @click="onDeselectAllRow">清空选择</el-button>
          <el-divider direction="vertical"></el-divider>
          <span class="ml5 b">已勾选:</span>
          <el-popover ref="popover" v-model="popoverVisible" placement="bottom-start" trigger="hover" width="350">
            <div class="pfs-gfa-audit-manage-content-acc-check-category-selection" v-if="popoverVisible">
              <div class="pfs-gfa-audit-manage-content-acc-check-category-option" :key="k" v-for="(e, k) in select">
                <div class="bs-color-primary f14 ell" :title="e.value">{{e.value}}</div>
                <div class="pfs-gfa-audit-manage-content-acc-check-category-option-remove" @click="onDeselectRow(k)">
                  <i class="fa fa-times-circle-o bs-color-red poi"></i>
                </div>
              </div>
            </div>
            <span class="bs-link-primary" slot="reference">{{selectRowLength}} 笔</span>
          </el-popover>
        </template>
      </div>
      <!-- 右侧分页区域 -->
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentPageChange" :current-page="page.currentPage" :page-sizes="page.sizes" :page-size="page.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="page.total" />
    </div>
  </div>
</template>
<script>
import { TABLE_HEADER_CELL_STYLE, TABLE_CELL_STYLE } from '@/mixin/page';
// TODO:mixin/page文件中引入单选多选相关公共方法
import { pagination, selectRow, selectAllRow, deselectRow, deselectAllRow, selectRowLength, isSelectRow, filterSelectRow,  } from '@/mixin/page';
import fetch from '@/config/fetch';
import util from '@/assets/js/util';
import {
  AUDIT_TYPE,
  AUDIT_STATUS,
  AUDITED_STATUS,
} from '@/modules/pfs/pfs-gfa/pfs-gfa-audit-manage/constant';
import { auditStatus, canPass, canReturn, publishAuditedStatusChange } from '@/modules/pfs/pfs-gfa/pfs-gfa-audit-manage/service';

export default {
  props: {
    contextInfo: Object, //上下文数据
    agencyFilter: Array,  //已过滤的单位数据
    audit: Function, //单位审核方法
  },
  mixins: [pagination],
  data() {
    return {
      query: {
        agencyCodeList: [], //公式编号
        reportId: '', //报表代码
      }, //查询条件
      agencyList: [], //报送主体数据
      reportList: [], //报表数据
      tableHeight: 0, //表格高度
      agencyProps: {
        id: 'agencyCode',
        label: 'agencyName',
        pid: 'parentCode',
        children: 'children',
      }, //报送主体字段属性
      reportProps: {
        id: 'code',
        label: 'name',
        children: 'children',
        pid: 'pcode',
      }, //报表字段属性
      select: {}, //已选的行数据  TODO:增加已选的行数据对象
      popoverVisible: false,  //已勾选弹框是否显示
      TABLE_HEADER_CELL_STYLE,
      TABLE_CELL_STYLE,
      AUDIT_TYPE,
    };
  },
  methods: {
    /**
     * 初始化页面
     * 1、获取报送主体数据
     * 2、获取报表数据
     * 3、获取表格数据
     */
    initPage() {
      this.getAgencyList();
      this.getReportList();
      this.getTableData();
    },
    /**
     * 获取报送主体数据
     */
    getAgencyList() {
      let { agencyCode, transType, taskId, mofDivCode, fiscalYear, fiscal, dwType } =
        this.contextInfo;
      fetch
        .post('/gfa/fr/gfa/org/agencyTree', {
          transType,
          groupId: taskId,
          mofDivCode,
          fiscalYear: fiscalYear || fiscal,
          fiscal: fiscalYear || fiscal,
          parentCode: agencyCode,
          dwType,
          agencyFilter: this.agencyFilter.map((e) => e.agencyCode),
        })
        .then(({ data }) => {
          data = data || [];
          this.agencyList = data.map((e) =>
            _.pick(e, ['agencyCode', 'agencyName', 'parentCode'])
          );
        })
        .catch((err) => {
          console.error(err);
          this.$message({
            type: 'error',
            message: err.msg,
          });
        });
    },
    /**
     * 获取报表列表
     */
    getReportList() {
      let { fiscalYear, transType, taskId, dwType } = this.contextInfo;
      fetch
        .post('/gfa/fr/gfa/task/getReportListByTaskId', {
          fiscalYear,
          transType,
          taskId,
          agencyCode: '*',
          agencyName: '*',
          dwType,
        })
        .then(({ data }) => {
          data = data || [];
          this.reportList = data;
        })
        .catch((err) => {
          console.error(err);
          this.$message({
            type: 'error',
            message: err.msg,
          });
        });
    },
    /**
     * 获取页面信息
     */
    getPageInfo() {
      this.page.currentPage = 1;
      this.pageData = [];
      this.$nextTick(() => {
        this.getTableData();
      });
    },
    /**
     * 设置页面信息
     * 1、设置数据总条数,表格数据,精简字段
     */
    setPageInfo({ total = 0, result = [] }) {
      this.page.total = total;
      this.pageData = result.map((e) => {
        return _.pick(e, [
          'id',
          'dwCode',
          'dwName',
          'reportCode',
          'reportName',
          'expFuncCode',
          'expFuncName',
          'reportItemName',
          'reportAmt',
          'subject',
          'accountAmt',
          'imbalanceAmt',
          'accountCause',
          'passCause',
          'accountStatus',
          'isSubmit',
        ]);
      });
    },
    /**
     * 获取表格数据
     */
    getTableData() {
      this.$loading();
      fetch
        .post('/gfa/fr/gfa/rpt/checkout/data', this.buildParams())
        .then(({ data }) => {
          this.$loadingClose();
          this.setPageInfo(data);
        })
        .catch((err) => {
          console.error(err);
          this.$loadingClose();
          this.$message({
            type: 'error',
            message: err.msg,
          });
        });
    },
    /**
     * 更新数据
     */
    updateData() {
      this.query.agencyCodeList = [];
      this.query.reportId = '';
      // TODO:更新表格数据时,需要取消选择全部行数据,一般用于表格初始化操作
      deselectAllRow(this.$data);
      this.getPageInfo();
      this.getAgencyList();
    },
    /**
     * 设置表格高度
     */
    setTableHeight() {
      this.tableHeight =
        $('.pfs-gfa-audit-manage-content-acc-check-category').height() - 70;
    },
    /**
     * 构建表格请求参数
     */
    buildParams() {
      let { agencyCode, mofDivCode, transType, taskId, fiscalYear, dwType } =
        this.contextInfo;
      let { agencyCodeList, reportId } = this.query;
      let { currentPage, pageSize } = this.page;
      return {
        dwCode: agencyCode,
        mofDivCode,
        transType,
        taskId,
        setYear: fiscalYear,
        transType,
        agyList: agencyCodeList,
        reportId,
        pageIndex: currentPage,
        pageSize,
        dwType,
        agencyFilter: this.agencyFilter.map((e) => e.agencyCode),
      };
    },
    /**
     * 设置选中行的数据
     */
    setSelectValue(rowData) {
      // TODO:设置选中行数据需要根据实际业务设置具体的字端
      return {
        id: rowData.id,
        isSubmit: rowData.isSubmit,
        accountStatus: rowData.accountStatus,
        value: `${rowData.reportName}--${rowData.expFuncCode}`,
      };
    },
    /**
     * 处理选择的报表变化
     */
    onReportChange(_value, data) {
      data = data || {};
      this.query.reportId = data.id;
    },
    /**
     * 处理选择
     */
    onSelectRow(rowData) {
      // TODO:调用公共方法处理行选择
      selectRow(this.select, rowData, 'id', this.setSelectValue);
    },
    /**
     * 处理全选
     */
    onSelectAllRow() {
      // TODO:调用公共方法处理全选
      selectAllRow(this.$data, this.select, this.tableData, 'id', this.setSelectValue);
    },
    /**
     * 处理取消全选
     */
    onDeselectAllRow() {
      // TODO:调用公共方法处理取消全选
      deselectAllRow(this.$data);
    },
    /**
     * 处理取消行选择
     */
    onDeselectRow(key) {
       // TODO:调用公共方法处理取消行选择
      deselectRow(this.select, key);
    },
    /**
     * 处理审核
     * 1、调用审核接口进行审核
     * 2、更改当前单位审核状态
     * 3、不通过操作,更新上级意见
     * 4、若为不通过操作,发布单位完成审核状态
     */
    async onAudit(auditType, rowData) {
      try {
        this.$loading();
        let passCause = await this.audit(auditType, [rowData.id]);
        rowData.accountStatus =
          auditType === AUDIT_TYPE.PASS
            ? AUDIT_STATUS.PASS
            : AUDIT_STATUS.NO_PASS;
        if (auditType === AUDIT_TYPE.NO_PASS) {
          rowData.passCause = passCause;
        }
        this.$message({
          type: 'success',
          message: '审核成功!',
        });
        if (auditType === AUDIT_TYPE.NO_PASS) {
          publishAuditedStatusChange(AUDITED_STATUS.UN_FINISHED, [rowData.agencyCode]);
        }
      } catch (err) {
        console.error(err);
        this.$message({
          type: 'error',
          message: err.msg,
        });
      } finally {
        this.$loadingClose();
      }
    },
    /**
     * 处理批量审核
     * 1、过滤出已选的数据里面有效的数据
     * 2、调用审核接口进行审核
     * 3、更改当前所选单位的审核状态;不通过操作,更新上级意见
     * 4、重置已选数据
     * 5、若为不通过操作,发布单位完成审核状态
     */
    async onBatchAudit(auditType) {
      try {
        this.$loading();
        let filterFunc = auditType === AUDIT_TYPE.PASS ? this.canPass : this.canReturn;
        // TODO:批量按钮操作时,过滤出有效的行数据
        let effectiveData = filterSelectRow(this.select, filterFunc);
        if (util.isEmpty(effectiveData)) {
          this.$message({
            type: 'warning',
            message: '未选择有效的数据!',
          });
          return;
        }
        let effectiveDataIds = effectiveData.map((e) => e.id);
        let passCause = await this.audit(auditType, effectiveDataIds);
        let accountStatus = auditType === AUDIT_TYPE.PASS ? AUDIT_STATUS.PASS : AUDIT_STATUS.NO_PASS;
        this.pageData.forEach((e) => {
          if (effectiveDataIds.includes(e.id)) {
            e.accountStatus = accountStatus;
            if (auditType === AUDIT_TYPE.NO_PASS) {
              e.passCause = passCause;
            }
          }
        });
         // TODO:批量按钮操作完毕时,应该取消选择全部行数据
        deselectAllRow(this.$data);
        this.$message({
          type: 'success',
          message: `审核成功,共处理 ${effectiveDataIds.length} 条数据!`,
        });
        if (auditType === AUDIT_TYPE.NO_PASS) {
          publishAuditedStatusChange(AUDITED_STATUS.UN_FINISHED, effectiveData.map((e) => e.agencyCode));
        }
      } catch (err) {
        console.error(err);
        this.$message({
          type: 'error',
          message: err.msg,
        });
      } finally {
        this.$loadingClose();
      }
    },
    /**
     * 审核状态显示
     */
    accountStatusDisplay(rowData) {
      return auditStatus(rowData.accountStatus);
    },
    /**
     * 是否可以通过
     */
    canPass(rowData) {
      let { isSubmit, accountStatus } = rowData;
      return canPass(isSubmit, accountStatus);
    },
    /**
     * 是否可以退回
     */
    canReturn(rowData) {
      let { isSubmit, accountStatus } = rowData;
      return canReturn(isSubmit, accountStatus);
    },
    /**
     * 是否选择当前行数据
     */
    isSelectRow(key) {
      //TODO:调用公共方法判断是否选择当前行数据
      return isSelectRow(this.select, key);
    },
  },
  computed: {
    /**
     * 已选行数据条数
     */
    selectRowLength() {
       // TODO:调用公共方法获取当前已选择的行数据条数
      return selectRowLength(this.select);
    },
  },
  mounted() {
    this.initPage();
    this.setTableHeight();
  },
};
</script>
<style lang="scss" scoped>
@import '~@/assets/style/variables.scss';
.pfs-gfa-audit-manage-content-acc-check-category {
  height: 100%;
  .pfs-gfa-audit-manage-content-acc-check-category-bottom {
    height: 35px;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }
}
.pfs-gfa-audit-manage-content-acc-check-category-selection {
  padding: 6px 0;
  overflow-y: auto;
  overflow-x: hidden;
  box-sizing: border-box;
  max-height: 300px;
  .pfs-gfa-audit-manage-content-acc-check-category-option {
    position: relative;
    padding: 0 40px 0 10px;
    height: 28px;
    line-height: 28px;
    &:hover {
      background-color: $-bs-bg-color;
    }
    .pfs-gfa-audit-manage-content-acc-check-category-option-remove {
      position: absolute;
      top: 0;
      right: 5px;
      font-size: 1.2em;
    }
  }
}
</style>