修改bbug

This commit is contained in:
2026-06-16 15:51:19 +08:00
parent 44949287e0
commit c1a382c255
7 changed files with 122 additions and 13 deletions

View File

@@ -18,8 +18,10 @@ import com.ruoyi.hrm.domain.vo.HrmMyApplyVo;
import com.ruoyi.hrm.domain.vo.HrmReimburseReqVo;
import com.ruoyi.hrm.domain.vo.HrmSealReqVo;
import com.ruoyi.hrm.domain.vo.HrmTravelReqVo;
import com.ruoyi.hrm.domain.HrmFlowInstance;
import com.ruoyi.hrm.mapper.HrmAppropriationReqMapper;
import com.ruoyi.hrm.mapper.HrmEmployeeMapper;
import com.ruoyi.hrm.mapper.HrmFlowInstanceMapper;
import com.ruoyi.hrm.mapper.HrmLeaveReqMapper;
import com.ruoyi.hrm.mapper.HrmReimburseReqMapper;
import com.ruoyi.hrm.mapper.HrmSealReqMapper;
@@ -32,7 +34,9 @@ import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@@ -48,6 +52,7 @@ public class HrmMyApplyController extends BaseController {
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
private final HrmFlowInstanceMapper flowInstanceMapper;
@GetMapping("/list")
public TableDataInfo<HrmMyApplyVo> list(String bizType, String status, String keyword, PageQuery pageQuery) {
@@ -80,6 +85,9 @@ public class HrmMyApplyController extends BaseController {
all.addAll(mapAppropriation(appropriationReqMapper.selectVoWithProjectList(buildAppropriationBo(emp.getEmpId(), status)), nickName));
}
// 用流程实例状态覆盖业务表状态,避免历史数据状态未同步
overrideStatusByFlowInstance(all);
if (keyword != null && !keyword.isEmpty()) {
String lower = keyword.toLowerCase();
all = all.stream().filter(v -> contains(v, lower)).collect(Collectors.toList());
@@ -93,6 +101,34 @@ public class HrmMyApplyController extends BaseController {
return TableDataInfo.build(page);
}
private void overrideStatusByFlowInstance(List<HrmMyApplyVo> all) {
if (all == null || all.isEmpty()) return;
Map<String, List<Long>> bizIdsByType = all.stream()
.filter(v -> v.getBizType() != null && v.getBizId() != null)
.collect(Collectors.groupingBy(
HrmMyApplyVo::getBizType,
Collectors.mapping(HrmMyApplyVo::getBizId, Collectors.toList())
));
Map<String, String> statusByKey = new HashMap<>();
bizIdsByType.forEach((bizType, bizIds) -> {
if (bizIds.isEmpty()) return;
List<HrmFlowInstance> insts = flowInstanceMapper.selectList(
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<HrmFlowInstance>()
.eq(HrmFlowInstance::getBizType, bizType)
.in(HrmFlowInstance::getBizId, bizIds)
);
for (HrmFlowInstance inst : insts) {
if (inst.getStatus() == null) continue;
statusByKey.merge(bizType + "_" + inst.getBizId(), inst.getStatus(),
(oldS, newS) -> oldS);
}
});
for (HrmMyApplyVo v : all) {
String s = statusByKey.get(v.getBizType() + "_" + v.getBizId());
if (s != null) v.setStatus(s);
}
}
private boolean contains(HrmMyApplyVo v, String lower) {
return Objects.toString(v.getTitle(), "").toLowerCase().contains(lower)
|| Objects.toString(v.getRemark(), "").toLowerCase().contains(lower)
@@ -109,7 +145,7 @@ public class HrmMyApplyController extends BaseController {
private List<HrmMyApplyVo> mapLeave(List<HrmLeaveReqVo> list, String nickName) { return list.stream().map(v -> toVo("leave", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapTravel(List<HrmTravelReqVo> list, String nickName) { return list.stream().map(v -> toVo("travel", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getRemark(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getPurpose() != null ? v.getPurpose() : v.getRemark(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapReimburse(List<HrmReimburseReqVo> list, String nickName) { return list.stream().map(v -> toVo("reimburse", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapAppropriation(List<HrmAppropriationReqVo> list, String nickName) { return list.stream().map(v -> toVo("appropriation", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime())).collect(Collectors.toList()); }

View File

@@ -6,6 +6,7 @@ import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
@Data
public class HrmFlowInstanceVo implements Serializable {
@@ -41,4 +42,7 @@ public class HrmFlowInstanceVo implements Serializable {
private Date createTime;
private String updateBy;
private Date updateTime;
/** 业务表回填的数据,用于列表关键信息展示 */
private Map<String, Object> bizData;
}

View File

@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.service.UserService;
@@ -27,7 +28,9 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@@ -42,6 +45,11 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
private final UserService userService;
private final HrmFlowCcMapper ccMapper;
private final HrmTravelReqMapper travelReqMapper;
private final HrmLeaveReqMapper leaveReqMapper;
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
private final ObjectMapper objectMapper;
private final ApplicationEventPublisher eventPublisher;
@Override
@@ -188,9 +196,55 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
}
}
}
fillInstanceBizData(result.getRecords());
return TableDataInfo.build(result);
}
@SuppressWarnings("unchecked")
private void fillInstanceBizData(List<HrmFlowInstanceVo> records) {
if (records == null || records.isEmpty()) return;
Map<String, List<Long>> bizIdsByType = records.stream()
.filter(v -> v.getBizType() != null && v.getBizId() != null)
.collect(Collectors.groupingBy(
HrmFlowInstanceVo::getBizType,
Collectors.mapping(HrmFlowInstanceVo::getBizId, Collectors.toList())
));
Map<String, Object> bizDataMap = new HashMap<>();
bizIdsByType.forEach((bizType, bizIds) -> {
if (bizIds.isEmpty()) return;
switch (bizType) {
case "leave":
leaveReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("leave_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "travel":
travelReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("travel_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "seal":
sealReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("seal_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "reimburse":
reimburseReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("reimburse_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
case "appropriation":
appropriationReqMapper.selectBatchIds(bizIds).forEach(d ->
bizDataMap.put("appropriation_" + d.getBizId(), objectMapper.convertValue(d, Map.class)));
break;
default:
break;
}
});
records.forEach(vo -> {
Object data = bizDataMap.get(vo.getBizType() + "_" + vo.getBizId());
if (data != null) {
vo.setBizData((Map<String, Object>) data);
}
});
}
@Override
public List<HrmFlowInstanceVo> queryList(HrmFlowInstanceBo bo) {
LambdaQueryWrapper<HrmFlowInstance> lqw = buildQueryWrapper(bo);

View File

@@ -4,13 +4,13 @@
<div slot="header" class="card-header">
<span>{{ bizTitle }}</span>
<div class="actions">
<el-button v-if="!preview" size="mini" icon="el-icon-arrow-left" @click="$router.back()">返回</el-button>
<el-button v-if="!isPreview" size="mini" icon="el-icon-arrow-left" @click="$router.back()">返回</el-button>
<el-button size="mini" icon="el-icon-refresh" @click="loadDetail">刷新</el-button>
<el-button v-if="!preview && canApprove" type="success" size="mini" :loading="actionLoading" @click="handleApprove">
<el-button v-if="!isPreview && canApprove" type="success" size="mini" :loading="actionLoading" @click="handleApprove">
通过
</el-button>
<el-button v-if="!preview && canApprove" type="danger" size="mini" :loading="actionLoading" @click="handleReject">
<el-button v-if="!isPreview && canApprove" type="danger" size="mini" :loading="actionLoading" @click="handleReject">
驳回
</el-button>
</div>
@@ -53,7 +53,7 @@
<ProjectInfo :info="detail" />
</el-card>
<div v-if="!preview">
<div v-if="!isPreview">
<div class="block-title">审批操作</div>
<el-card class="inner-card" shadow="never">
<div v-if="currentTask" class="btn-row">
@@ -75,7 +75,7 @@
<span>操作汇报</span>
</div>
<div v-if="!preview" class="comment-form">
<div v-if="!isPreview" class="comment-form">
<editor v-model="commentForm.commentContent" placeholder="填写操作汇报(可选)" />
<file-upload v-model="commentForm.attachments" />
<div class="form-actions">
@@ -89,7 +89,7 @@
<div class="comment-meta">
<span class="comment-operator">{{ item.createByName }}</span>
<span class="comment-time">{{ item.createTime }}</span>
<el-button v-if="!preview && isSelf(item)" type="danger" size="mini" @click="handleDeleteComment(item.commentId)"
<el-button v-if="!isPreview && isSelf(item)" type="danger" size="mini" @click="handleDeleteComment(item.commentId)"
:loading="buttonLoading">删除</el-button>
</div>
</div>
@@ -160,6 +160,9 @@ export default {
}
},
computed: {
isPreview () {
return this.preview || !!this.$route?.query?.preview
},
currentBizId () {
return this.bizId
},

View File

@@ -46,7 +46,7 @@ export default {
if (routePath) {
this.$router.push({
path: routePath,
query: { bizId: bizId }
query: { bizId: bizId, preview: 1 }
})
} else {
this.$message.warning('无法确定申请类型对应的详情页面')

View File

@@ -50,7 +50,6 @@
stripe
border
@row-dblclick="handleRowClick">
<el-table-column label="编号" prop="instId" width="80" />
<el-table-column label="类型" width="70">
<template slot-scope="scope">
<el-tag :type="getTypeTagType(scope.row.bizType)" size="mini">{{ getTypeText(scope.row.bizType) }}</el-tag>
@@ -80,6 +79,9 @@
<el-table-column label="申请时间" prop="createTime" width="140">
<template slot-scope="scope">{{ formatDate(scope.row.createTime) }}</template>
</el-table-column>
<el-table-column label="结束时间" width="140">
<template slot-scope="scope">{{ formatFinishTime(scope.row) }}</template>
</el-table-column>
<el-table-column label="耗时" width="80">
<template slot-scope="scope">{{ formatElapsed(scope.row) }}</template>
</el-table-column>
@@ -174,7 +176,7 @@ export default {
case 'travel':
return `${b.travelType || '出差'} · ${b.destination || '未填目的地'}${b.startTime ? ' · ' + this.formatDate(b.startTime) : ''}`
case 'seal':
return `${b.sealType || '用印'}${b.fileName ? ' · ' + b.fileName : ''}${b.useReason ? ' · ' + b.useReason : ''}`
return `${b.sealType || '用印'}${b.purpose ? ' · ' + b.purpose : ''}`
case 'reimburse':
return `${b.reimburseType || '报销'} · ¥${b.totalAmount != null ? b.totalAmount : 0}${b.reason ? ' · ' + b.reason : ''}`
case 'appropriation':
@@ -192,9 +194,19 @@ export default {
}
return '-'
},
flowEndTime (row) {
const finalStatus = ['approved', 'rejected', 'revoked', 'finished', 'complete']
if (row.bizType === 'travel' && row.actualEndTime) return row.actualEndTime
if (finalStatus.includes(row.status)) return row.updateTime || null
return null
},
formatFinishTime (row) {
const end = this.flowEndTime(row)
return end ? this.formatDate(end) : '-'
},
formatElapsed (row) {
if (!row.createTime) return '-'
const end = row.finishTime || row.endTime || Date.now()
const end = this.flowEndTime(row) || Date.now()
const ms = new Date(end).getTime() - new Date(row.createTime).getTime()
if (ms <= 0) return '-'
const h = ms / 3600000

View File

@@ -32,8 +32,8 @@
</el-card>
<!-- 盖章操作审批通过后显示 -->
<div v-if="canStamp" class="block-title">盖章操作</div>
<el-card v-if="canStamp" class="inner-card" shadow="never">
<div v-if="canStamp && !$route.query.preview" class="block-title">盖章操作</div>
<el-card v-if="canStamp && !$route.query.preview" class="inner-card" shadow="never">
<div class="stamp-section">
<div class="stamp-config">
<el-form :model="stampForm" label-width="120px" size="small">