vue3+antd+ts setup语法糖封装a-table组件

需求:页面有多处地方需要使用a-table,封装成公用组件

子页面:

        1. defineProps中接受父页面columns,dataList,total

        2. 子页面定义pagination分页,defineEmits中定义父页面分页change事件

代码如下:

<template>
  <div>
    <a-table
      :columns="columns"
      :data-source="dataList"
      :pagination="pagination"
      bordered
      size="middle"
      @change="handleTableChange"
    >
      <template #bodyCell="{ column, text, record }">
        <template v-if="column.dataIndex === 'ip'">
          <a>{{ text }}</a>
        </template>

        <template v-if="column.dataIndex === 'tags'">
          <div style="display: flex; flex-wrap: wrap; gap: 5px">
            <div v-for="tag in record.tags" :key="tag">
              <a-tooltip placement="top">
                <template #title>
                  <span>{{ tag.hasTagTip }}</span>
                </template>
                <span>{{ tag.name }}</span>
              </a-tooltip>
            </div>
          </div>
        </template>
      </template>
    </a-table>
  </div>
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import type { ColumnsType } from 'ant-design-vue/es/table'
defineOptions({
  name: '',
})

// 使用withDefaults可以给defineProps定义的属性指定ts类型,解决columns ts类型报错
const props = withDefaults(
  defineProps<{
    columns: ColumnsType<any>
    dataList: Array<string>
    total: Number
  }>(),
  {},
)

// 对props.total进行监听,因为defineProps中定义的值没有响应性,如果父组件列表请求还没结束就渲染
// 子页面的话,会导致props已经赋了初始值,不会再重新赋值.
watch(
  () => props.total,
  (newVal) => {
    if (newVal) {
      return (pagination.value.total = newVal)
    }
  },
)

// 分页定义在props中没办法单独给pagination中的total赋值,只能定义在外面
const pagination = ref<any>({
  total: props.total,
  current: 1,
  pageSize: 10, //每页中显示10条数据
  showSizeChanger: true,
  pageSizeOptions: ['10', '20', '50', '100'], //每页中显示的数据
  showTotal: (total) => `共有 ${total} 条数据`, //分页中显示总的数据
})

const emit = defineEmits(['handleTableChange'])

// table分页change事件
const handleTableChange = (pageSize) => {
  // 切换分页后需要将新的分页属性赋值一遍,因为change事件返回的pageSize中没有showTotal()方法, 
  // 所以要用Object.assign()
  Object.assign(pagination.value, pageSize)
  emit('handleTableChange', pageSize)
}
</script>

<style lang="less" scoped></style>

父页面:

        1. import引入子页面

        2. 父页面分别定义colums,datalist,total,三个table接口入参

        3. 父页面定义分页change事件,传入type区分分页和接口入参

代码如下 :

<template>
  <div class="content">
    <div class="content-tab">
      <a-tabs v-model:activeKey="activeKey" @change="handChange">
        <a-tab-pane key="1" tab="ICO情报">
          <h3>文件情报</h3>
          <CustomTable
            key="fileKey"
            :columns="columns"
            :data-list="fileDataList"
            :total="fileTotalNum"
            @handle-table-change="(pagination) => handleTableChange(pagination, 'file')"
          />
          <h3>域名情报</h3>
          <CustomTable
            key="'domainKey'"
            :columns="domainColumns"
            :data-list="domainDataList"
            :total="domainTotalNum"
            @handle-table-change="(pagination) => handleTableChange(pagination,'domain')"
          />
          <h3>IP情报</h3>
          <CustomTable
            key="ipKey"
            :columns="ipColumns"
            :data-list="ipDataList"
            :total="ipTotalNum"
            @handle-table-change="(pagination) => handleTableChange(pagination, 'ip')"
          />
        </a-tab-pane>
      </a-tabs>
    </div>
  </div>
</template>

<script setup lang="ts">
import { h, ref } from 'vue'
import { UserOutlined, LeftOutlined, LoadingOutlined } from '@ant-design/icons-vue'
import CustomTable from './apt-table/index.vue'
const activeKey = ref('1')
const datalist = ref([
  {
    link: '',
    create_time: '',
    title: '',
    author: '',
    description: '',
  },
])

const fileTotalNum = ref()
const domainTotalNum = ref()
const ipTotalNum = ref()

// 文件情报list
const fileDataList = ref([])
// 域名情报table list
const domainDataList = ref([])
// IP情报table list
const ipDataList = ref([])

const columns = ref([
  {
    title: '文件HASA',
    dataIndex: 'sha256',
    width: '50%',
  },
  {
    title: '文件类型',
    dataIndex: 'file_type',
    width: '10%',
  },
  {
    title: '威胁情报',
    dataIndex: 'tags',
    width: '40%',
  },
])
const domainColumns = ref([
  {
    title: '域名信息',
    dataIndex: 'domain',
  },
  {
    title: '威胁情报',
    dataIndex: 'tags',
  },
])
const ipColumns = ref([
  {
    title: 'IP地址',
    dataIndex: 'ip',
  },
  {
    title: '地理信息',
    dataIndex: 'location',
  },
  {
    title: 'ASN',
    dataIndex: 'asn',
  },
  {
    title: '威胁情报',
    dataIndex: 'tags',
  },
])

defineOptions({
  title: '海莲花组织近期攻击手法分析',
})

const paramsId = ref<any>('')
// 定义三个table接口查询入参
const createQueryParam = (id) => {
  return ref({
    id,
    page: 1,
    size: 10,
  })
}
const activityQueryParam = createQueryParam(paramsId)
const fileQueryParam = createQueryParam(paramsId)
const domainQueryParam = createQueryParam(paramsId)
const ipQueryParam = createQueryParam(paramsId)

function onload() {
  paramsId.value = route.params.id
  getTrajectoryList()
}
onload()

// tabs change事件
const handChange = (targetKey) => {
  getICOIntelligence('')
}

// 获取ICO情报列表
const getICOIntelligence = async (type) => {
  try {
    let requestList: Promise<any>[] = []

    if (type === 'file') {
      requestList.push(apiGetAptDetailDocument(fileQueryParam.value))
    } else if (type === 'domain') {
      requestList.push(apiGetAptDetailDomainIntel(domainQueryParam.value))
    } else if (type === 'ip') {
      requestList.push(apiGetAptDetailIpIntel(ipQueryParam.value))
    } else {
      requestList = [
        apiGetAptDetailDocument(fileQueryParam.value),
        apiGetAptDetailDomainIntel(domainQueryParam.value),
        apiGetAptDetailIpIntel(ipQueryParam.value),
      ]
    }
    const result = await Promise.all(requestList)

    if (type === 'file') {
      fileDataList.value = result[0].data
      fileTotalNum.value = result[0].total
    } else if (type === 'domain') {
      domainDataList.value = result[0].data
      domainTotalNum.value = result[0].total
    } else if (type === 'ip') {
      ipDataList.value = result[0].data
      ipTotalNum.value = result[0].total
    } else {
      fileDataList.value = result[0].data
      fileTotalNum.value = result[0].total
      domainDataList.value = result[1].data
      domainTotalNum.value = result[1].total
      ipDataList.value = result[2].data
      ipTotalNum.value = result[2].total
    }
  } catch (error) {
    console.error(error)
  }
}

// table子组件分页change事件
const handleTableChange = (pagination, type) => {
  if (type === 'file') {
    fileQueryParam.value.page = pagination.current
    fileQueryParam.value.size = pagination.pageSize
  } else if (type === 'domain') {
    domainQueryParam.value.page = pagination.current
    domainQueryParam.value.size = pagination.pageSize
  } else if (type === 'ip') {
    ipQueryParam.value.page = pagination.current
    ipQueryParam.value.size = pagination.pageSize
  }

  getICOIntelligence(type)
}
</script>

<style lang="less" scoped></style>

踩过的坑:

        1. 分页在父页面定义了三个,导致子页面调用父分页分页change事件后需要判断给三个table分页和入参重新赋值,代码过于冗余。

        2. 使用Promise.all()同时处理三个接口,分页切换的时候需要判断调用那个接口,且对返回的结果也要单独判断赋值,建议可以为三个table请求单独定义方法。

        3. 子页面在defineProps接收分页并赋初始值,没办法使父页面首次加载的total具有响应性,只能单独分开,在defineProps中接受total,使用ref()定义分页数据,再将props.total监听(监听为了解决defineProps没有响应性问题)赋值给分页pagination对象。

        4. 在defineProps中定义columns时eslint提示ts类型格式不对,使用withDefaults为defineProps中的columns重新定义类型。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值