背景:小程序开发申请流程。使用flowable流程框架。用户需要在后台统揽用户申请的汇总表。
设计思路:通过查询流程实例分页查询获取数据 , 其中可以通过查询条件进行查询 ,查询条件是流程申请时添加到流程变量当中的,方便进行查询
具体内容。
- 涉及到前端页面和后端代码,还有导出部分实现。
- PC页面
- 后端代码:此部分为具体实现流程。
java
@Override
public TableDataInfo<WfTaskVo> selectPageInitiatorProcessList(ProcessQuery processQuery, PageQuery pageQuery) {
Page<WfTaskVo> page = new Page<>();
HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
.orderByProcessInstanceStartTime()
.desc();
// 使用buildProcessSearch拼接查询条件
ProcessUtils.buildProcessSearch(historicProcessInstanceQuery, processQuery);
int offset = pageQuery.getPageSize() * (pageQuery.getPageNum() - 1);
List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery
.includeProcessVariables()
.listPage(offset, pageQuery.getPageSize());
page.setTotal(historicProcessInstanceQuery.count());
List<WfTaskVo> taskVoList = new ArrayList<>();
for (HistoricProcessInstance hisIns : historicProcessInstances) {
WfTaskVo taskVo = new WfTaskVo();
taskVo.setProcInsId(hisIns.getId());
taskVo.setProcDefId(hisIns.getProcessDefinitionId());
taskVo.setProcDefName(hisIns.getProcessDefinitionName());
taskVo.setCreateTime(hisIns.getStartTime());
taskVo.setFinishTime(hisIns.getEndTime());
// 计算耗时
if (Objects.nonNull(hisIns.getEndTime())) {
taskVo.setDuration(DateUtils.getDatePoor(hisIns.getEndTime(), hisIns.getStartTime()));
} else {
taskVo.setDuration(DateUtils.getDatePoor(DateUtils.getNowDate(), hisIns.getStartTime()));
}
// 获取发起人信息
Long userId = Long.parseLong(hisIns.getStartUserId());
String nickName = userService.selectNickNameById(userId);
taskVo.setStartUserId(userId);
taskVo.setStartUserName(nickName);
Object name = hisIns.getProcessVariables().get("name");
if (name != null) {
taskVo.setName(name.toString());
}
Object projectId = hisIns.getProcessVariables().get(BusiConstants.PROJECT_ID);
if (projectId != null) {
taskVo.setProjectId(projectId.toString());
}
taskVoList.add(taskVo);
}
page.setRecords(taskVoList);
return TableDataInfo.build(page);
}
- 此部分为添加的查询条件处理。
ProcessUtils.buildProcessSearch(historicProcessInstanceQuery, processQuery);
对入参进行处理
java
public static void buildProcessSearch(Query<?, ?> query, ProcessQuery process) {
if (query instanceof ProcessDefinitionQuery) {
buildProcessDefinitionSearch((ProcessDefinitionQuery) query, process);
} else if (query instanceof TaskQuery) {
buildTaskSearch((TaskQuery) query, process);
} else if (query instanceof HistoricTaskInstanceQuery) {
buildHistoricTaskInstanceSearch((HistoricTaskInstanceQuery) query, process);
} else if (query instanceof HistoricProcessInstanceQuery) {
buildHistoricProcessInstanceSearch((HistoricProcessInstanceQuery) query, process);
}
}
...
public static void buildHistoricProcessInstanceSearch(HistoricProcessInstanceQuery query, ProcessQuery process) {
Map<String, Object> params = process.getParams();
// 流程标识
if (StringUtils.isNotBlank(process.getProcessKey())) {
query.processDefinitionKey(process.getProcessKey());
}
// 流程名称
if (StringUtils.isNotBlank(process.getProcessName())) {
query.processDefinitionName(process.getProcessName());
}
// 流程名称
if (StringUtils.isNotBlank(process.getCategory())) {
query.processDefinitionCategory(process.getCategory());
}
if (params.get("beginTime") != null && params.get("endTime") != null) {
query.startedAfter(DateUtils.parseDate(params.get("beginTime")));
query.startedBefore(DateUtils.parseDate(params.get("endTime")));
}
// 判断项目id
if (ObjectUtil.isNotEmpty(params.get("projectId"))) {
query.variableValueEquals("projectId", params.get("projectId"));
}
// 判断病种id
if (ObjectUtil.isNotEmpty(params.get("diseaseInfoId"))) {
query.variableValueEquals("diseaseInfoId", params.get("diseaseInfoId"));
}
// 模糊查询姓名
if (ObjectUtil.isNotEmpty(params.get("name"))) {
query.variableValueLike("name", "%" + params.get("name").toString() + "%");
}
// 查询省份
if (ObjectUtil.isNotEmpty(params.get("provinceCode"))) {
query.variableValueEquals("provinceCode", params.get("provinceCode"));
}
// 流程状态(已完成未完成)
if (ObjectUtil.isNotEmpty(params.get("status"))) {
if ("1".equals(params.get("status"))) {
query.finished();
}else {
query.unfinished();
}
}
}
导出方案及实现
- 核心内容: 大模型给的方案中,我使用了分批导出。相比于延长超时时间、分页导出等更合理。是使用前端进行导出的方式,只获取后端接口数据。
js
/** 导出按钮操作 */
async handleExport() {
try {
// 显示进度对话框
this.exportProgress.visible = true;
this.exportProgress.percentage = 0;
this.exportProgress.currentBatch = 0;
this.exportProgress.totalBatches = 0;
this.exportProgress.currentCount = 0;
this.exportProgress.totalCount = 0;
const batchSize = 1000; // 每批1000条数据
let allData = [];
let currentPage = 1;
let hasMore = true;
// 构建基础查询参数
const baseParams = {
name: this.queryParams.name,
projectId: this.queryParams.projectId,
startUserName: this.queryParams.startUserName,
status: this.queryParams.status
};
// 添加日期范围参数
if (this.dateRange && this.dateRange.length === 2) {
baseParams.beginTime = this.dateRange[0];
baseParams.endTime = this.dateRange[1];
} else {
// 如果没有选择时间范围,设置默认值(最近30天)
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);
baseParams.beginTime = startDate.toISOString().slice(0, 19).replace('T', ' ');
baseParams.endTime = endDate.toISOString().slice(0, 19).replace('T', ' ');
}
// 先获取总数,用于计算进度
const countResponse = await fetchInitiatorList({
pageNum: 1,
pageSize: 1,
params: baseParams
});
if (countResponse.code === 200) {
this.exportProgress.totalCount = countResponse.total || 0;
this.exportProgress.totalBatches = Math.ceil(this.exportProgress.totalCount / batchSize);
}
// 分批获取数据
while (hasMore) {
const batchParams = {
pageNum: currentPage,
pageSize: batchSize,
params: baseParams
};
// 更新进度信息
this.exportProgress.currentBatch = currentPage;
this.exportProgress.currentCount = allData.length;
this.exportProgress.percentage = Math.round((allData.length / this.exportProgress.totalCount) * 100);
const response = await fetchInitiatorList(batchParams);
if (response.code === 200 && response.rows && response.rows.length > 0) {
allData = allData.concat(response.rows);
currentPage++;
// 检查是否还有更多数据
hasMore = response.rows.length === batchSize;
// 添加小延迟,避免请求过于频繁
await new Promise((resolve) => setTimeout(resolve, 100));
} else {
hasMore = false;
}
}
if (allData.length > 0) {
// 更新最终进度
this.exportProgress.currentCount = allData.length;
this.exportProgress.percentage = 100;
// 显示最终进度
this.$message.info(`数据获取完成,共 ${allData.length} 条,正在生成Excel文件...`);
// 格式化数据为Excel格式
const excelData = this.formatDataForExcel(allData);
// 生成Excel文件
this.generateAndDownloadExcel(excelData);
this.$message.success(`导出成功,共导出 ${allData.length} 条数据`);
} else {
this.$message.warning('没有数据可导出');
}
// 关闭进度对话框
setTimeout(() => {
this.exportProgress.visible = false;
}, 2000);
} catch (error) {
console.error('导出失败:', error);
// 关闭进度对话框
this.exportProgress.visible = false;
if (error.message && error.message.includes('timeout')) {
this.$message.error('导出超时,请尝试缩小查询范围或联系管理员');
} else {
this.$message.error('导出失败,请重试');
}
}
},