首页 > 其他分享 >Vue3.2+TS+arco-design报表封装,所有的报表页面皆可用一个组件进行完成

Vue3.2+TS+arco-design报表封装,所有的报表页面皆可用一个组件进行完成

时间:2024-11-21 10:43:40浏览次数:3  
标签:flex const 报表 TS Vue3.2 params import true page

多功能表格统一封装

在我们进行后台管理系统开发的时候,一定少不了报表的开发,

报表无非就是筛选,统计,分页等功能,但是一旦报表多了起来之后,每次都去开发一个表格,每次都去写一个table,还要加分页,就显得非常没有必要

所以我封装了一个多功能表格,以后每次,只需要导入这个组件,便可以实现报表的统一管理

1.如何使用

我们把筛选项目和表格抽离为两个组件,相关接口调用放在外部,以便统一处理,为什么不把筛选也封装,因为筛选项不一致,会有很多不同的参数,所以筛选项必须抽离出来

筛选的参数使用v-model绑定,方便自动更新参数的数据,相关的page参数使用hooks封装

<template>
  <div class="table">
    <div class="filter">
      <Filter v-model:params="params" @onSearch="onSearch" @onReset="onReset" />
    </div>
    <div class="datainfo">
      <basciTable
        :columns="columns"
        :page="page"
        :loading="loading"
        :data="tableData"
        @updatePageChange="pageChange"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue';
import { useTableData, getTimeRange } from '../page-hooks/index.js';
import { getPersonStatistics } from '@/services/fpcs-service';
import Filter from './filter.vue';
import basciTable from '../components/basci-table.vue';

const { page } = useTableData();

const loading = ref(false);

const params = reactive({
  fullName: '', // 人员类型
  idCard: '',
  policeOrgId: '',
  time: getTimeRange(),
  warningTag: 'YKONG',
  hasChild: false,
});

const columns = [
  {
    title: '姓名',
    dataIndex: 'fullName',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '身份证号',
    dataIndex: 'idCard',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '等级',
    dataIndex: 'controlLevelName',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '类别',
    dataIndex: 'personCategoryName',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '状态',
    dataIndex: 'controlStatusName',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '户籍',
    dataIndex: 'domicilePlaceAddress',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '责任',
    dataIndex: 'policeOrgName',
    ellipsis: true,
    tooltip: true,
  },
  {
    title: '责任222',
    dataIndex: 'policeResponsibleStaffName',
    ellipsis: true,
    tooltip: true,
  },
];

const tableData = ref([]);
const onSearch = async () => {
  loading.value = true;
  const warningStartTime = params.time[0];
  const warningEndTime = params.time[1];
  const info = {
    ...params,
    ...page.value,
    warningStartTime,
    warningEndTime,
  } as { [key: string]: any };
  delete info.time;
  try {
    const res = await getPersonStatistics(info);
    if (res.code === '200') {
      tableData.value = res.data.records;
      page.value.total = res.data.total;
    }
  } catch (error) {
    console.log(error);
  } finally {
    loading.value = false;
  }
};

const pageChange = (val: any) => {
  page.value = val;
  onSearch();
};

const onReset = () => {
  params.fullName = '';
  params.idCard = '';
  params.warningTag = 'YKONG';
  params.time = getTimeRange();
  params.hasChild = false;
  params.policeOrgId = '';
  onSearch();
};

onMounted(() => {
  onSearch();
});
<style scoped lang="less">
.table {
  height: 100%;
  display: flex;
  flex-direction: column;
  .datainfo {
    flex: 1;
    min-height: 0;
    height: 100%;
    :deep(.arco-tabs) {
      height: 100%;
      display: flex;
      flex-direction: column;
      .arco-tabs-content,
      .arco-tabs-content-list,
      .arco-tabs-pane {
        height: 100%;
      }
    }
  }
}
</style>

page参数的封装
import { ref } from 'vue';
import dayjs from 'dayjs';

// 通用表格数据

export const useTableData = () => {
  const page = ref({
    total: 0,
    current: 1,
    size:15
  })
  return {
    page
  }
}

// 通用时间范围
export const getTimeRange = () => {
  const endTime = dayjs();  // 当前时间
  const startTime = endTime.subtract(1, 'month');  // 当前时间的前一个月
  return [startTime.format('YYYY-MM-DD HH:mm:ss'), endTime.format('YYYY-MM-DD HH:mm:ss')];
}

// 通用时间范围 不带时分秒
export const getTimeRangeInDay = () => {
  const endTime = dayjs();  // 当前时间
  const startTime = endTime.subtract(1, 'month');  // 当前时间的前一个月
  return [startTime.format('YYYY-MM-DD'), endTime.format('YYYY-MM-DD')];
}

筛选参数的封装,使用computed属性之后,使用get和set把相关的参数的更新暴露出去
<template>
  <div class="filter-box">
    <a-form
      ref="formRef"
      :model="filterParams"
      label-align="right"
      auto-label-width
      @keyup.enter.prevenDefault="onSearch"
    >
      <a-row :gutter="8">
        <a-col :span="6">
          <a-form-item label="姓名" show-colon>
            <a-input
              v-model="filterParams.fullName"
              allow-clear
              placeholder="请输入姓名"
            />
          </a-form-item>
        </a-col>
        <a-col :span="5">
          <a-form-item field="idCard" label="身份证号" show-colon>
            <a-input
              v-model="filterParams.idCard"
              allow-clear
              placeholder="请输入"
            />
          </a-form-item>
        </a-col>
        <a-col :span="7">
          <a-form-item label="责任派出所" show-colon>
            <div class="org-select">
              <OrgTreeSelect
                v-model="filterParams.policeOrgId"
                placeholder="请选择责任派出所"
              />
              <a-checkbox v-model="filterParams.hasChild">是否拥有下级</a-checkbox>
            </div>
          </a-form-item>
        </a-col>
        <a-col :span="6">
          <a-form-item field="dateVal" label="预警时间" show-colon>
            <a-range-picker
              v-model="filterParams.time"
              :allow-clear="false"
              show-time
              style="width: 100%"
            />
          </a-form-item>
        </a-col>
        <a-col :span="6">
          <a-form-item label="统计类型" show-colon>
            <a-select
              v-model="filterParams.warningTag"
              :options="type"
              placeholder="请选择责任单位"
            />
          </a-form-item>
        </a-col>
                <a-col :span="18">
          <a-form-item>
            <div class="btn-group">
              <a-button
                type="primary"
                style="margin-left: 5px"
                @click="onSearch"
              >
                <template #icon><icon-search /></template>
                查询
              </a-button>
              <a-button style="margin-left: 5px" @click="onReset">
                <template #icon><icon-refresh /></template>
                重置
              </a-button>
            </div>
          </a-form-item>
        </a-col>
      </a-row>
    </a-form>
  </div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import OrgTreeSelect from '@/view/personnel-back/components/org-tree-select.vue';
const props = defineProps({
  params: {
    default: () => ({}),
  },
});

const type = [
  {
    label: '云控人员',
    value: 'YKONG',
  },
  {
    label: '涉京人员',
    value: 'SRJING',
  },
  {
    label: '涉晋人员',
    value: 'SJIN ',
  },
  {
    label: '历史人员',
    value: '',
  },
];

const emits = defineEmits(['update:params', 'onSearch', 'onReset']);
const filterParams = computed<any>({
  get() {
    return props.params;
  },
  set(val) {
    emits('update:params', val);
  },
});
const onSearch = () => {
  emits('onSearch');
};
const onReset = () => {
  emits('onReset');
};
</script>
<style scoped lang="less">
.filter-box {
  padding: 10px 10px 0 10px;
  :deep(.arco-form) {
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
    .btn-group {
      display: flex;
      justify-content: flex-end;
      width: 100%;
    }
    .org-select{
      width: 100%;
      display: flex;
      .arco-checkbox{
        width: 150px;
      }
    }
  }
}
</style>
最后是表格的封装,无非就是控制列,控制分页,控制数据更新,控制当页面高度缩小,分页组件会自动上拉
<template>
  <div class="contain-box">
    <div class="tablebox">
      <a-table
        ref="tableRef"
        :bordered="{headerCell:headerBorder}"
        :scroll="{ y: '100%' }"
        :data="data"
        :columns="columns"
        :loading="props.loading"
        :pagination="false"
      ></a-table>
    </div>
    <div v-if="props.isNeedPage" class="pation">
      <a-pagination
        :current="currentPage?.current"
        :total="currentPage?.total"
        :page-size="currentPage?.size"
        :page-size-options="[15, 30, 45, 60, 75]"
        show-total
        show-jumper
        show-page-size
        @change="pageChange"
        @page-size-change="pageSizeChange"
      />
    </div>
  </div>
</template>
<script setup lang="ts">
import { computed } from 'vue';

const props = defineProps({
  columns: {
    type: Array,
    default: () => [],
  },
  page: {
    type: Object,
    default: () => {},
  },
  data: {
    type: Array,
    default: () => [],
  },
  loading: {
    type: Boolean,
    default: false,
  },
  headerBorder: {
    type: Boolean,
    default: false,
  },
  isNeedPage: {
    type: Boolean,
    default: true,
  }
});

const currentPage = computed(() => props.page);

const emits = defineEmits(['updatePageChange']);
const pageChange = (page: number) => {
  emits('updatePageChange', { ...props.page, current: page });
};

const pageSizeChange = (pageSize: number) => {
  emits('updatePageChange', { ...props.page, size: pageSize });
};
</script>
<style scoped lang="less">
.contain-box {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 10px;
  .tablebox {
    flex: 1;
    min-height: 0;
  }
  .pation {
    display: flex;
    justify-content: flex-end;
    padding: 10px;
  }
}
</style>

现在,咱们得多功能的组件就封装好了,还能自动控制需不需要分页

如果有其他的功能,也可以在这个基础上不断新增

标签:flex,const,报表,TS,Vue3.2,params,import,true,page
From: https://blog.csdn.net/m0_56986233/article/details/143935423

相关文章

  • Visual Studio 的程序打包工具Installer Projects
    我们常常写好应用程序,但是不知道如何交付到用户手里面,所以今天写的这篇文章就是怎么交付过去。我们编辑好程序后,编译会生成可执行文件,但是我们调用一些库,也是文件,不可能给别人一个.zip压缩包,所以这个时候,我们就需要将他变成一个安装程序,让用户进行安装,甚至里面有一些自定义操......
  • 快照接口 isRepositoryExists单元测试
    好的,为了编写restoreSnapshotIndices方法的单元测试,我们需要考虑以下几个方面:准备测试数据:创建一个RestoreSnapshotIndicesRequest对象,包含多个SnapShotDTO对象。模拟依赖服务:使用Mockito模拟restHighLevelClient和indicesRestoreMapper等依赖服务的行为。执行测......
  • ehcarts 实战小计-1
    需求展示未来未来36个月(等分为3个时间范围)的经济效益趋势,3个等分时间区域在趋势图上方常显,不同时间区域之间通过灰色虚线间隔开;鼠标hover趋势图每个1/3区域,对应区域会有以下3个效果:时间范围卡片高亮;趋势图上方展示对应指标;趋势图展示阴影效果;鼠标hoveror点击趋势图无t......
  • ArkTS组件结构和状态管理
    1.认识基本的组件结构ArkTS通过装饰器@Component和@Entry装饰struct关键字声明的数据结构,构成一个自定义组件自定义组件中提供了一个build函数,开发者需要在函数内以链式调用的方式进行基本的UI描述,UI描述的方法请参考UI描述规范srtuct-自定义组件基于struct实现......
  • 24-live555模拟RTSP流
    live555环境搭建(1.)二进制文件下载http://www.live555.com/mediaServer/(2.)源码下载安装https://github.com/rgaufman/live555#编译./genMakefileslinux-64bitmake-j4(3.)运行./live555MediaServer(4.)运行目录下放置mkv、ts\h264等文件(5.)vlc播放rtsp流rtsp://ip......
  • 多目标优化算法:多目标极光优化算法(Multi-objective Polar Lights Optimization, MOPLO
    一、极光优化算法极光优化算法(PolarLightsOptimization,PLO)是2024年提出的一种新型的元启发式优化算法,它从极光这一自然现象中汲取灵感。极光是由太阳风中的带电粒子在地球磁场的作用下,与地球大气层中的气体分子碰撞而产生的光显示。PLO算法通过模拟这些带电粒子的运动......
  • C:\Windows\Fonts 文件夹是 Windows 操作系统中存放系统字体的默认目录。它包含了操
    C:\Windows\Fonts文件夹是Windows操作系统中存放系统字体的默认目录。它包含了操作系统用来显示文本的各种字体文件。字体文件是计算机中用来渲染和显示字符的文件格式,它们对操作系统、应用程序、网页等的界面和文字显示非常重要。1. C:\Windows\Fonts文件夹是什么?内容:这......
  • python+requests
    python+request一、介绍request库(1)requests是用python语言编写的简单易用的http库,用来做接口测试的库;(2)接口测试自动化库有哪些?requests、urllib、urllib2、urllib3、httplib等(最受欢迎的是requests)(3)安装request库方式一:dos下pip:命令:pipinstallrequests方法二:pycharm......
  • 【K8S系列】imagePullSecrets配置正确,但docker pull仍然失败,进一步排查详细步骤
    如果imagePullSecrets配置正确,但在执行dockerpull命令时仍然失败,可能存在以下几种原因。以下是详细的排查步骤和解决方案。1.检查Docker登录凭证确保你使用的是与imagePullSecrets中相同的凭证进行Docker登录:1.1直接登录在命令行中,执行以下命令:docker......
  • 五款报表工具对比:找到最适合你的数据分析利器
    概述在现代数据驱动的商业环境中,报表工具是企业决策的重要助力。本文精选了五款报表工具,包括山海鲸报表在内,详细介绍了它们的功能特色、使用场景以及各自的优缺点,帮助大家快速找到适合自身需求的解决方案。1.山海鲸报表简介:山海鲸报表是一款国产报表工具,主打轻量化、便捷性,支......