1、需求背景
展示一个任务详情页,这个页面有两个入口
-
任务创建页点击详情进入;
-
任务开发页点击详情进入。
进入任务详情后,详情中展示子任务列表,子任务列表还要根据不同的页面来源(任务创建页还是任务开发页)和不同的任务状态展示不同的数据列。
以下举出一个示例。
例如,由任务创建页进入任务详情时:
-
未开始的任务,任务详情中展示的列为:软件名称,提交要求
-
已开始未提交的任务,任务详情中展示的列为:软件名称,软件版本,当前状态
-
已提交的任务,任务详情中展示的列为:软件名称,软件版本,提交版本,提交人,提交时间,审核操作
由任务开发页进入任务详情时:
-
未开始的任务,任务详情中展示的列为:软件名称,提交要求、开发时间
-
已开始未提交的任务,任务详情中展示的列为:软件名称,软件版本,当前状态,操作列
-
已提交的任务,任务详情中展示的列为:软件名称,软件版本,提交版本,提交人,提交时间,审核结果
以下就是实现子任务列表组件的过程。
2、实现思路
2.1 组件规划
使用Table组件,我这里使用的是ant-design-vue,3.x的版本。核心要实现的就是如何根据任务状态展示不同的数据列。有三种思路。
1)写多个table,通过v-if结合任务状态来判断显示那个table;
2)写一个table,根据页面来源和任务状态过滤出要显示的数据列;
3)写一个table,列出所有的数据列,在template中通过v-if集合页面来源和任务状态控制显隐。
第一种思路实现起来比较简单,但是会有很多重复代码;第三种会有很多template中的判断;这里我采用了第二种思路。
2.2 数据映射关系
第二种思路,需要梳理数据列和任务状态的关系,首先,将全量的数据列定义出来。
软件名称、提交要求、软件版本、最新进展、操作列、提交版本、提交人、提交时间、审核操作、开发时间、当前状态、审核结果。定义为一组数组。
const allColumns = [
{
title: '软件名称',
dataIndex: 'softwareName',
width: 150
},
{
title: '提交要求',
dataIndex: 'require',
width: 150
},
{
title: '软件版本',
dataIndex: 'softwareVersion',
width: 150
},
{
title: '操作列',
dataIndex: 'operation',
},
{
title: '提交版本',
dataIndex: 'version',
},
{
title: '提交人',
dataIndex: 'updateUser',
},
{
title: '提交时间',
dataIndex: 'updateTime',
width: 150
},
{
title: '审核操作',
dataIndex: 'auditOperation',
},
{
title: '开发时间',
dataIndex: 'startTime',
},
{
title: '当前状态',
dataIndex: 'currentStatus',
},
{
title: '审核结果',
dataIndex: 'result',
}
]
1)任务状态和表格数据列的关系如下表所示
页面来源source | 任务状态taskStatus | 数据列dataIndex |
任务创建页source=create | 未开始taskStatus=1 | 软件名称,提交要求 |
已开始未提交taskStatus=2 | 软件名称,软件版本,当前状态 | |
已提交taskStatus=3 | 软件名称,软件版本,提交版本,提交人,提交时间,审核操作 | |
任务开发页source=develop | 未开始taskStatus=1 | 软件名称,提交要求、开发时间 |
已开始未提交taskStatus=2 | 软件名称,软件版本,当前状态,操作列 | |
已提交taskStatus=3 | 软件名称,软件版本,提交版本,提交人,提交时间,审核结果 |
将以上对应关系,生成一个JSON的映射关系
const columnsMap = {
/**
* module:{
* statuskey:[item1,item2...]
* }
*/
create: {
// 1-未开始,2-已开始未提交,3-已提交
1: ['softwareName', 'require'],
2: ['softwareName', 'softwareVersion', 'currentStatus'],
3: ['softwareName', 'softwareVersion', 'version', 'updateUser', 'updateTime', 'auditOperation']
},
develop: {
1: ['softwareName', 'require', 'startTime'],
2: ['softwareName', 'softwareVersion', 'currentStatus', 'operation'],
3: ['softwareName', 'softwareVersion', 'version', 'updateUser', 'updateTime', 'result']
}
}
2)写一个方法,根据页面来源和任务状态返回数据列。在template中使用计算属性绑定数据列。
const getColumsByStatus = (fnModule, status) => {
let res = []
let transStatus = status.toString()
if (columnsMap[fnModule]) {
let arr = columnsMap[fnModule][transStatus]
allColumns.forEach(item => {
if (arr.includes(item.dataIndex)) {
res.push(item)
}
})
}
return res
}
// 计算属性
const computedCols = computed(() => {
return getColumsByStatus(query.taskSource, query.taskStatus)
})
//template中的绑定
<Table :columns="computedCols" :data-source="computedDataSource" bordered :pagination="false"></Table>
3、代码实现
页面来源和任务状态参数是通过页面的URL进行传递的,然后通过route.query进行访问。完整代码实现如下所示。
<template>
<Table :columns="computedCols" :data-source="computedDataSource" bordered :pagination="false">
<template #bodyCell="{ column, text, record }">
<template v-if="column.dataIndex === 'auditOperation'">
<div class="editable-row-operations">
<a>审核</a>
</div>
</template>
<template v-if="column.dataIndex === 'operation'">
<div class="editable-row-operations">
<a>操作</a>
</div>
</template>
</template>
</Table>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import { Table } from 'ant-design-vue'
import { getTaskDetailList } from '@/api/server'
const route = useRoute()
const query = route.query
const dataSource = ref<any[]>([])
onMounted(() => {
initData()
})
const initData = async () => {
// 调接口获取子任务列表
let res = await getTaskDetailList({
taskId: query.taskId
})
dataSource.value = res?.data || []
}
// 计算属性,返回表格的数据列
const computedCols = computed(() => {
return getColumsByStatus(query.taskSource, query.taskStatus)
})
// 定义所有的列
const allColumns = [
{
title: '软件名称',
dataIndex: 'softwareName',
width: 150
},
{
title: '提交要求',
dataIndex: 'require',
width: 150
},
{
title: '软件版本',
dataIndex: 'softwareVersion',
width: 150
},
{
title: '操作列',
dataIndex: 'operation',
},
{
title: '提交版本',
dataIndex: 'version',
},
{
title: '提交人',
dataIndex: 'updateUser',
},
{
title: '提交时间',
dataIndex: 'updateTime',
width: 150
},
{
title: '审核操作',
dataIndex: 'auditOperation',
},
{
title: '开发时间',
dataIndex: 'startTime',
},
{
title: '当前状态',
dataIndex: 'currentStatus',
},
{
title: '审核结果',
dataIndex: 'result',
}
]
// 定义页面来源、任务状态和数据列的映射关系
const columnsMap = {
/**
* module:{
* statuskey:[item1,item2...]
* }
*/
create: {
// 1-未开始,2-已开始未提交,3-已提交
1: ['softwareName', 'require'],
2: ['softwareName', 'softwareVersion', 'currentStatus'],
3: ['softwareName', 'softwareVersion', 'version', 'updateUser', 'updateTime', 'auditOperation']
},
develop: {
1: ['softwareName', 'require', 'startTime'],
2: ['softwareName', 'softwareVersion', 'currentStatus', 'operation'],
3: ['softwareName', 'softwareVersion', 'version', 'updateUser', 'updateTime', 'result']
}
}
// 根据页面来源和任务状态获取数据列的方法
const getColumsByStatus = (fnModule, status) => {
let res = []
let transStatus = status.toString()
if (columnsMap[fnModule]) {
let arr = columnsMap[fnModule][transStatus]
allColumns.forEach(item => {
if (arr.includes(item.dataIndex)) {
res.push(item)
}
})
}
return res
}
</script>
<style scoped lang="scss">
.editable-row-operations a {
margin-right: 8px;
}
</style>