前端效果图
后端操作
首先根据需要合并的字段进行分组且分页查询,然后再连表查询。
注意这里与常规的分页查询不同,常规的分页查询是对整个sql语句执行完之后,对整个结果进行分页处理,而我们这里需要先对分组之后的结果进行分页处理。所以需要改变分页的逻辑。代码如下:
首先继承MySqlDialect,重写getPageSql方法,主要思路对sql语句进行字符串替换,在指定位置进行分页逻辑拼接
public class MySqlDialectCustom extends MySqlDialect {
@Override
public String getPageSql(String sql, Page page, CacheKey pageKey) {
Pattern compileFixed = Pattern.compile("/\\*fixed\\*/");
String compileLimit = "/\\*limit\\*/";
if (compileFixed.matcher(sql).find()) {
if (page.getStartRow() == 0) {
sql = sql.replaceFirst(compileLimit, " LIMIT ? ");
} else {
sql = sql.replaceFirst(compileLimit, " LIMIT ?, ? ");
}
return sql;
}
return super.getPageSql(sql, page, pageKey);
}
}
修改配置文件加上配置
# PageHelper分页插件
pagehelper:
helperDialect: xxx.xxx.util.MySqlDialectCustom #上面类的全限定类名
在需要修改分页位置的地方加入占位标志即可;比如按照本例,是根据日期和工号进行合并操作。所以需要先根据日期和工号进行分组操作得到组数据再进行分组操作然后将得到的结果当做一张子表再和原表进行内连接操作得到其他需要的字段
<select id="selectPieceworkInfoList" parameterType="PiecewortInfoDTO" resultType="PieceworkInfoVO">
/*fixed*/
select rpi.id, rpi.piecework_date, rpi.product_id, dept_thrid_id, dept_fourth_id, rpi.staff_id,temp.pieceworkFee
from rfw_piecework_info rpi
INNER join (SELECT staff_id,piecework_date, sum(unit_price*capacity_num) as pieceworkFee FROM rfw_piecework_info
GROUP BY staff_id, piecework_date /*limit*/) temp on rpi.staff_id=temp.staff_id and
rpi.piecework_date=temp.piecework_date
order by rpi.piecework_date,rpi.staff_id
</select>
这样操作之后得到的结果确实是按分组之后的结果进行了分页处理,比如一页10条数据,上述sql一般会查询出大于10条的数据,然后经过前端处理之后合并成10条数据进行展示。
注意:上述查询的结果确实进行了分页处理,但是插件自带的总数配置还是整个sql语句的总数 不是我们分组分页之后的总数,所以需要额外再写一条sql统计分组之后的总条数
前端处理
主要使用elementui的table组件的span-method方法进行合并单元格处理
以下是通义千问提供的代码示例,可直接运行本地查看调整效果,并参考改造自己的代码
问:假设前端elementui有个table组件,里面有日期,工号,产品字段,现在需要根据日期和工号字段进行合并操作,产品不合并还是多行展示,如果日期和工号相同,就合并日期和工号使用table的span-method,生成完整的vue文件
答:
<template>
<div id="app">
<el-table
:data="tableData"
style="width: 100%"
border
:span-method="arraySpanMethod"
>
<el-table-column prop="date" label="日期" width="180"></el-table-column>
<el-table-column prop="workNo" label="工号" width="180"></el-table-column>
<el-table-column prop="product" label="产品"></el-table-column>
</el-table>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
tableData: [
{ date: '2023-04-01', workNo: '001', product: 'Product A' },
{ date: '2023-04-01', workNo: '001', product: 'Product B' },
{ date: '2023-04-02', workNo: '002', product: 'Product C' },
{ date: '2023-04-03', workNo: '003', product: 'Product D' },
{ date: '2023-04-03', workNo: '003', product: 'Product E' },
],
};
},
methods: {
arraySpanMethod({ row, column, rowIndex, columnIndex }) {
// 仅针对日期和工号列进行处理
if (columnIndex < 2) {
const currentKey = `${row.date}-${row.workNo}`;
const prevRow = rowIndex > 0 ? this.tableData[rowIndex - 1] : null;
const prevKey = prevRow ? `${prevRow.date}-${prevRow.workNo}` : '';
// 如果当前行与上一行的日期和工号相同,则计算需要的rowspan
if (currentKey === prevKey) {
// 由于我们不希望产品列合并,直接返回让当前列为非展示状态即可
return { rowspan: 0, colspan: 0 };
} else {
// 查找相同日期和工号的连续行数
let rowspan = 1;
while(rowIndex + rowspan < this.tableData.length &&
`${this.tableData[rowIndex + rowspan].date}-${this.tableData[rowIndex + rowspan].workNo}` === currentKey) {
rowspan++;
}
return { rowspan, colspan: 1 };
}
}
// 对于产品列,不需要特殊处理,直接返回默认的单个单元格
return { rowspan: 1, colspan: 1 };
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
效果图如下: