推送项目重构代码
This commit is contained in:
@@ -68,11 +68,6 @@ public class HrmAppropriationReqController extends BaseController {
|
||||
return R.ok(service.queryList(bo));
|
||||
}
|
||||
|
||||
@GetMapping("/ocr-health")
|
||||
public R<Boolean> ocrHealth() {
|
||||
return R.ok(invoiceOcrService.isAlive());
|
||||
}
|
||||
|
||||
@PostMapping("/ocr-by-oss")
|
||||
public R<HrmInvoiceOcrResultVo> ocrByOss(@RequestParam @NotNull Long ossId) {
|
||||
return R.ok(invoiceOcrService.recognizeByOssId(ossId));
|
||||
|
||||
@@ -68,11 +68,6 @@ public class HrmReimburseReqController extends BaseController {
|
||||
return R.ok(service.queryList(bo));
|
||||
}
|
||||
|
||||
@GetMapping("/ocr-health")
|
||||
public R<Boolean> ocrHealth() {
|
||||
return R.ok(invoiceOcrService.isAlive());
|
||||
}
|
||||
|
||||
@PostMapping("/ocr-by-oss")
|
||||
public R<HrmInvoiceOcrResultVo> ocrByOss(@RequestParam @NotNull Long ossId) {
|
||||
return R.ok(invoiceOcrService.recognizeByOssId(ossId));
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.ruoyi.hrm.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 申请提交后产生的事件:通知监听方(如 IM 推送)给当前待办的审批人发提醒。
|
||||
* 由 fad-hrm 发布,ruoyi-oa 监听后调 ImSendService 推送。
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class ApprovalRequestedEvent {
|
||||
/** 业务类型:seal / leave / travel / reimburse / appropriation */
|
||||
private final String bizType;
|
||||
/** 业务主键 */
|
||||
private final Long bizId;
|
||||
/** 流程实例ID */
|
||||
private final Long instId;
|
||||
/** 待审批人 OA userId */
|
||||
private final Long assigneeUserId;
|
||||
/** 申请发起人 OA userId */
|
||||
private final Long startUserId;
|
||||
}
|
||||
@@ -3,17 +3,10 @@ package com.ruoyi.hrm.service;
|
||||
import com.ruoyi.hrm.domain.vo.HrmInvoiceOcrResultVo;
|
||||
|
||||
/**
|
||||
* 发票OCR识别服务(调用Python OCR微服务)
|
||||
* 发票识别服务:本地解析电子发票 PDF。
|
||||
*/
|
||||
public interface IHrmInvoiceOcrService {
|
||||
|
||||
/**
|
||||
* 通过ossId识别发票
|
||||
*/
|
||||
/** 根据 ossId 解析发票 PDF */
|
||||
HrmInvoiceOcrResultVo recognizeByOssId(Long ossId);
|
||||
|
||||
/**
|
||||
* 检查OCR服务是否存活
|
||||
*/
|
||||
boolean isAlive();
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ import com.ruoyi.hrm.domain.bo.HrmFlowInstanceBo;
|
||||
import com.ruoyi.hrm.domain.vo.HrmFlowInstanceVo;
|
||||
import com.ruoyi.hrm.domain.vo.HrmFlowTaskVo;
|
||||
import com.ruoyi.hrm.domain.vo.HrmTravelReqVo;
|
||||
import com.ruoyi.hrm.event.ApprovalRequestedEvent;
|
||||
import com.ruoyi.hrm.mapper.*;
|
||||
import com.ruoyi.hrm.service.IHrmFlowInstanceService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -40,6 +42,7 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
|
||||
private final UserService userService;
|
||||
private final HrmFlowCcMapper ccMapper;
|
||||
private final HrmTravelReqMapper travelReqMapper;
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
@Override
|
||||
public HrmFlowInstanceVo queryById(Long instId) {
|
||||
@@ -84,6 +87,11 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
|
||||
task.setBizId(bo.getBizId());
|
||||
taskMapper.insert(task);
|
||||
|
||||
// 发布事件 → ruoyi-oa 监听后推 IM 通知 + 快捷跳转
|
||||
eventPublisher.publishEvent(new ApprovalRequestedEvent(
|
||||
bo.getBizType(), bo.getBizId(), inst.getInstId(),
|
||||
bo.getManualAssigneeUserId(), bo.getStartUserId()));
|
||||
|
||||
return inst.getInstId();
|
||||
}
|
||||
|
||||
@@ -131,6 +139,11 @@ public class HrmFlowInstanceServiceImpl implements IHrmFlowInstanceService {
|
||||
task.setBizId(bo.getBizId());
|
||||
taskMapper.insert(task);
|
||||
|
||||
// 发布事件 → ruoyi-oa 监听后推 IM 通知 + 快捷跳转
|
||||
eventPublisher.publishEvent(new ApprovalRequestedEvent(
|
||||
bo.getBizType(), bo.getBizId(), inst.getInstId(),
|
||||
assignees.get(0), bo.getStartUserId()));
|
||||
|
||||
return inst.getInstId();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +1,61 @@
|
||||
package com.ruoyi.hrm.service.impl;
|
||||
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.hrm.domain.vo.HrmInvoiceOcrResultVo;
|
||||
import com.ruoyi.hrm.service.IHrmInvoiceOcrService;
|
||||
import com.ruoyi.oss.factory.OssFactory;
|
||||
import com.ruoyi.system.mapper.SysOssMapper;
|
||||
import com.ruoyi.system.domain.vo.SysOssVo;
|
||||
import com.ruoyi.system.mapper.SysOssMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.*;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.text.PDFTextStripper;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 发票OCR识别服务实现(调用Python OCR微服务)
|
||||
* 发票识别服务实现:直接解析电子发票 PDF 文本,无外部模型依赖。
|
||||
* 仅支持 PDF(电子普通发票 / 电子专用发票 / 全电数电票)。
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
|
||||
|
||||
|
||||
|
||||
@Value("${fad.ocr.url}")
|
||||
String ocrUrl;
|
||||
|
||||
@Value("${fad.ocr.api-key}")
|
||||
String apiKey;
|
||||
|
||||
private final SysOssMapper sysOssMapper;
|
||||
|
||||
/** "价税合计(小写)¥123.45" 这种小写金额 */
|
||||
private static final Pattern P_TOTAL = Pattern.compile(
|
||||
"(?:价税合计|小写)[^0-9¥¥]{0,30}[¥¥]?\\s*([0-9,]+\\.[0-9]{2})");
|
||||
|
||||
/** 开票日期:2024年01月01日 或 2024-01-01 */
|
||||
private static final Pattern P_DATE = Pattern.compile(
|
||||
"开票日期[:: ]*([0-9]{4}[年\\-/][0-9]{1,2}[月\\-/][0-9]{1,2}日?)");
|
||||
|
||||
/** 发票类型抬头 */
|
||||
private static final Pattern P_TYPE = Pattern.compile(
|
||||
"(电子(?:普通)?发票|增值税电子(?:普通|专用)发票|电子发票([^)]+)|数电(?:普通)?发票|普通发票|专用发票)");
|
||||
|
||||
/** 销售方名称:兼顾 "销售方名称:xxx"、"销 售 方 名称:xxx"、新版"销售方信息名称:xxx" */
|
||||
private static final Pattern P_SELLER = Pattern.compile(
|
||||
"销\\s*售\\s*方[^名]*名\\s*称[:: ]*([^\\n\\r]+?)(?=\\s{2,}|纳税人|统一社会|地址|开户|$)");
|
||||
|
||||
/** 明细行金额(行末两列:金额 税率% 税额 或 金额 税率% 价税合计) */
|
||||
private static final Pattern P_LINE_AMOUNT = Pattern.compile(
|
||||
"([\\u4e00-\\u9fa5A-Za-z0-9()()\\-·.\\*\\s]{2,40}?)\\s+" + // 名称
|
||||
"([0-9,]+\\.[0-9]{2})\\s+" + // 金额(不含税)
|
||||
"(\\d{1,2}%|免税|不征税|\\*)\\s+" + // 税率
|
||||
"([0-9,]+\\.[0-9]{2})"); // 税额
|
||||
|
||||
@Override
|
||||
public HrmInvoiceOcrResultVo recognizeByOssId(Long ossId) {
|
||||
SysOssVo oss = sysOssMapper.selectVoById(ossId);
|
||||
@@ -51,6 +63,11 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
|
||||
throw new ServiceException("附件不存在: " + ossId);
|
||||
}
|
||||
|
||||
String suffix = StringUtils.defaultIfBlank(oss.getFileSuffix(), "").toLowerCase().replace(".", "");
|
||||
if (!"pdf".equals(suffix)) {
|
||||
throw new ServiceException("仅支持 PDF 电子发票,当前文件类型: " + suffix);
|
||||
}
|
||||
|
||||
byte[] fileBytes;
|
||||
try (InputStream in = OssFactory.instance().getObjectContent(oss.getUrl())) {
|
||||
fileBytes = IoUtil.readBytes(in);
|
||||
@@ -58,170 +75,101 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
|
||||
throw new ServiceException("读取附件失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
String fileName = StringUtils.defaultIfBlank(oss.getOriginalName(), oss.getFileName());
|
||||
return callOcrService(fileBytes, fileName, oss.getFileSuffix());
|
||||
return parsePdf(fileBytes);
|
||||
}
|
||||
|
||||
private HrmInvoiceOcrResultVo callOcrService(byte[] fileBytes, String fileName, String fileSuffix) {
|
||||
|
||||
if (StringUtils.isBlank(ocrUrl)) {
|
||||
throw new ServiceException("OCR服务地址未配置,请检查 fad.ocr.url");
|
||||
}
|
||||
|
||||
// 推断 content-type
|
||||
String suffix = StringUtils.defaultIfBlank(fileSuffix, "").toLowerCase().replace(".", "");
|
||||
String contentType;
|
||||
switch (suffix) {
|
||||
case "pdf":
|
||||
contentType = "application/pdf";
|
||||
break;
|
||||
case "png":
|
||||
contentType = "image/png";
|
||||
break;
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
contentType = "image/jpeg";
|
||||
break;
|
||||
default:
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
|
||||
// 构建 multipart 请求
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
if (StringUtils.isNotBlank(apiKey)) {
|
||||
headers.set("X-API-Key", apiKey);
|
||||
}
|
||||
|
||||
final String finalContentType = contentType;
|
||||
final String finalFileName = StringUtils.defaultIfBlank(fileName, "invoice" + "." + suffix);
|
||||
ByteArrayResource fileResource = new ByteArrayResource(fileBytes) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return finalFileName;
|
||||
}
|
||||
};
|
||||
|
||||
HttpHeaders fileHeaders = new HttpHeaders();
|
||||
fileHeaders.setContentType(MediaType.parseMediaType(finalContentType));
|
||||
HttpEntity<ByteArrayResource> filePart = new HttpEntity<>(fileResource, fileHeaders);
|
||||
|
||||
MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
|
||||
body.add("file", filePart);
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
ResponseEntity<String> response;
|
||||
try {
|
||||
response = restTemplate.postForEntity(ocrUrl + "/v1/invoice/ocr", requestEntity, String.class);
|
||||
/** 直接从 PDF 中抽文本并按发票常见版面解析字段 */
|
||||
private HrmInvoiceOcrResultVo parsePdf(byte[] bytes) {
|
||||
String text;
|
||||
try (PDDocument doc = PDDocument.load(new ByteArrayInputStream(bytes))) {
|
||||
PDFTextStripper stripper = new PDFTextStripper();
|
||||
stripper.setSortByPosition(true);
|
||||
stripper.setLineSeparator("\n");
|
||||
text = stripper.getText(doc);
|
||||
} catch (Exception e) {
|
||||
log.error("[OCR] 调用OCR服务失败 url={} error={}", ocrUrl, e.getMessage());
|
||||
throw new ServiceException("OCR服务调用失败: " + e.getMessage());
|
||||
log.error("[Invoice] PDF 解析失败", e);
|
||||
throw new ServiceException("PDF 解析失败: " + e.getMessage()
|
||||
+ "。若为扫描件,请提供电子发票原始 PDF。");
|
||||
}
|
||||
if (StringUtils.isBlank(text)) {
|
||||
throw new ServiceException("无法从 PDF 提取文本,可能为扫描件,请上传电子发票原始 PDF。");
|
||||
}
|
||||
|
||||
if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null) {
|
||||
throw new ServiceException("OCR服务返回异常: " + response.getStatusCode());
|
||||
}
|
||||
|
||||
return parseOcrResponse(response.getBody());
|
||||
}
|
||||
|
||||
private HrmInvoiceOcrResultVo parseOcrResponse(String responseBody) {
|
||||
HrmInvoiceOcrResultVo result = new HrmInvoiceOcrResultVo();
|
||||
try {
|
||||
JSONObject root = JSON.parseObject(responseBody);
|
||||
JSONObject data = root.getJSONObject("data");
|
||||
if (data == null) {
|
||||
return result;
|
||||
}
|
||||
result.setInvoiceType(firstGroup(P_TYPE, text));
|
||||
result.setInvoiceDate(firstGroup(P_DATE, text));
|
||||
result.setSellerName(cleanSeller(firstGroup(P_SELLER, text)));
|
||||
result.setTotalAmount(parseBigDecimal(firstGroup(P_TOTAL, text)));
|
||||
|
||||
result.setInvoiceType(getFieldValue(data, "invoice_type"));
|
||||
result.setSellerName(getFieldValue(data, "seller_name"));
|
||||
result.setInvoiceDate(getFieldValue(data, "invoice_date"));
|
||||
List<HrmInvoiceOcrResultVo.Item> items = parseLineItems(text);
|
||||
|
||||
String totalAmountStr = getFieldValue(data, "amount_with_tax");
|
||||
if (StringUtils.isBlank(totalAmountStr)) {
|
||||
totalAmountStr = getFieldValue(data, "total_amount");
|
||||
}
|
||||
result.setTotalAmount(parseBigDecimal(totalAmountStr));
|
||||
|
||||
// 解析明细行
|
||||
List<HrmInvoiceOcrResultVo.Item> items = new ArrayList<>();
|
||||
JSONArray lineItems = data.getJSONArray("line_items");
|
||||
if (lineItems != null) {
|
||||
for (int i = 0; i < lineItems.size(); i++) {
|
||||
JSONObject li = lineItems.getJSONObject(i);
|
||||
if (li == null) continue;
|
||||
String name = getStringOrFieldValue(li, "project_name");
|
||||
if (StringUtils.isBlank(name)) continue;
|
||||
|
||||
HrmInvoiceOcrResultVo.Item item = new HrmInvoiceOcrResultVo.Item();
|
||||
item.setItemName(name);
|
||||
// 行项目金额取价税合计:税前金额 + 税额
|
||||
BigDecimal preAmt = parseBigDecimal(getStringOrFieldValue(li, "amount"));
|
||||
BigDecimal taxAmt = parseBigDecimal(getStringOrFieldValue(li, "tax_amount"));
|
||||
BigDecimal withTax = null;
|
||||
if (preAmt != null || taxAmt != null) {
|
||||
withTax = (preAmt != null ? preAmt : BigDecimal.ZERO)
|
||||
.add(taxAmt != null ? taxAmt : BigDecimal.ZERO);
|
||||
}
|
||||
item.setAmount(withTax != null ? withTax : preAmt);
|
||||
item.setTaxRate(getStringOrFieldValue(li, "tax_rate"));
|
||||
items.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有明细行但有总金额,生成一个汇总条目
|
||||
if (items.isEmpty() && result.getTotalAmount() != null) {
|
||||
HrmInvoiceOcrResultVo.Item item = new HrmInvoiceOcrResultVo.Item();
|
||||
String seller = StringUtils.defaultIfBlank(result.getSellerName(), "发票款项");
|
||||
item.setItemName(seller);
|
||||
item.setAmount(result.getTotalAmount());
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
result.setItems(items);
|
||||
} catch (Exception e) {
|
||||
log.warn("[OCR] 解析OCR响应失败: {}", e.getMessage());
|
||||
// 兜底:解析不到明细但有总价 → 生成一条汇总
|
||||
if (items.isEmpty() && result.getTotalAmount() != null) {
|
||||
HrmInvoiceOcrResultVo.Item item = new HrmInvoiceOcrResultVo.Item();
|
||||
item.setItemName(StringUtils.defaultIfBlank(result.getSellerName(), "发票款项"));
|
||||
item.setAmount(result.getTotalAmount());
|
||||
items.add(item);
|
||||
}
|
||||
result.setItems(items);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 从 {value: "...", confidence: 0.9} 结构取值,或直接取字符串 */
|
||||
private String getFieldValue(JSONObject obj, String key) {
|
||||
Object val = obj.get(key);
|
||||
if (val == null) return null;
|
||||
if (val instanceof JSONObject) {
|
||||
return ((JSONObject) val).getString("value");
|
||||
/** 抽明细行:在"货物名称 … 合计"之间逐行匹配 */
|
||||
private List<HrmInvoiceOcrResultVo.Item> parseLineItems(String text) {
|
||||
List<HrmInvoiceOcrResultVo.Item> items = new ArrayList<>();
|
||||
// 定位明细表区间,找不到也没关系,直接全文匹配也能跑
|
||||
int begin = indexOfAny(text, "项目名称", "货物或应税劳务", "货物名称");
|
||||
int end = indexOfAny(text, "合\\s*计", "价税合计", "(大写)", "(大写)");
|
||||
String area = (begin >= 0 && end > begin) ? text.substring(begin, end) : text;
|
||||
|
||||
for (String line : area.split("\\n")) {
|
||||
line = line.trim();
|
||||
if (line.length() < 6) continue;
|
||||
Matcher m = P_LINE_AMOUNT.matcher(line);
|
||||
if (!m.find()) continue;
|
||||
HrmInvoiceOcrResultVo.Item item = new HrmInvoiceOcrResultVo.Item();
|
||||
String name = m.group(1).trim().replaceAll("^\\*[^*]+\\*", ""); // 去掉 *类别* 前缀
|
||||
BigDecimal preTax = parseBigDecimal(m.group(2));
|
||||
String rate = m.group(3);
|
||||
BigDecimal tax = parseBigDecimal(m.group(4));
|
||||
BigDecimal withTax = (preTax != null ? preTax : BigDecimal.ZERO)
|
||||
.add(tax != null ? tax : BigDecimal.ZERO);
|
||||
item.setItemName(name);
|
||||
item.setTaxRate(rate);
|
||||
item.setAmount(withTax);
|
||||
items.add(item);
|
||||
}
|
||||
return val.toString();
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
|
||||
if (StringUtils.isBlank(ocrUrl)) return false;
|
||||
try {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
ResponseEntity<String> resp = restTemplate.getForEntity(ocrUrl + "/health", String.class);
|
||||
return resp.getStatusCode().is2xxSuccessful();
|
||||
} catch (Exception e) {
|
||||
log.warn("[OCR] 健康检查失败: {}", e.getMessage());
|
||||
return false;
|
||||
}
|
||||
private static String firstGroup(Pattern p, String s) {
|
||||
if (s == null) return null;
|
||||
Matcher m = p.matcher(s);
|
||||
return m.find() ? m.group(1).trim() : null;
|
||||
}
|
||||
|
||||
private String getStringOrFieldValue(JSONObject obj, String key) {
|
||||
Object val = obj.get(key);
|
||||
if (val == null) return null;
|
||||
if (val instanceof JSONObject) {
|
||||
return ((JSONObject) val).getString("value");
|
||||
private static int indexOfAny(String text, String... patterns) {
|
||||
int min = -1;
|
||||
for (String p : patterns) {
|
||||
Matcher m = Pattern.compile(p).matcher(text);
|
||||
if (m.find()) {
|
||||
int idx = m.start();
|
||||
if (min < 0 || idx < min) min = idx;
|
||||
}
|
||||
}
|
||||
return val.toString();
|
||||
return min;
|
||||
}
|
||||
|
||||
private BigDecimal parseBigDecimal(String raw) {
|
||||
private static String cleanSeller(String s) {
|
||||
if (s == null) return null;
|
||||
// 去掉抬头里常见的"名称:"残留 + 末尾空白和半角空格序列
|
||||
s = s.replaceAll("^[::\\s]+", "").trim();
|
||||
// 截断到第一个非中文/字母/数字/常见公司符号块
|
||||
String[] tail = s.split("\\s{2,}");
|
||||
return tail.length > 0 ? tail[0].trim() : s;
|
||||
}
|
||||
|
||||
private static BigDecimal parseBigDecimal(String raw) {
|
||||
if (StringUtils.isBlank(raw)) return null;
|
||||
try {
|
||||
return new BigDecimal(raw.replace(",", "").replace("¥", "").replace("¥", "").trim());
|
||||
@@ -229,4 +177,5 @@ public class HrmInvoiceOcrServiceImpl implements IHrmInvoiceOcrService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -121,6 +121,9 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
|
||||
return baseMapper.selectVoWithProjectList(bo);
|
||||
}
|
||||
|
||||
/** 用印申请固定审批人:陆永强(信息化部,userId=1858417253738815490) */
|
||||
private static final Long SEAL_FIXED_APPROVER_USER_ID = 1858417253738815490L;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public HrmSealReqVo insertByBo(HrmSealReqBo bo) {
|
||||
@@ -129,22 +132,18 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
|
||||
validEntityBeforeSave(add);
|
||||
boolean ok = baseMapper.insert(add) > 0;
|
||||
|
||||
// 只要传入了 tplId 或 manualAssigneeUserId,就代表需要启动流程
|
||||
Long tplId = bo.getTplId() != null ? bo.getTplId() : bo.getFlowTplId();
|
||||
boolean shouldStartFlow = tplId != null || bo.getManualAssigneeUserId() != null;
|
||||
|
||||
HrmSealReqVo bean = BeanUtil.toBean(add, HrmSealReqVo.class);
|
||||
if (ok && shouldStartFlow) {
|
||||
if (ok) {
|
||||
// 用印申请审批人写死成陆永强,忽略前端传的 tplId / manualAssigneeUserId
|
||||
HrmFlowStartBo start = new HrmFlowStartBo();
|
||||
start.setTplId(tplId);
|
||||
start.setManualAssigneeUserId(bo.getManualAssigneeUserId());
|
||||
start.setTplId(null);
|
||||
start.setManualAssigneeUserId(SEAL_FIXED_APPROVER_USER_ID);
|
||||
start.setBizType("seal");
|
||||
start.setBizId(add.getBizId());
|
||||
start.setStartUserId(LoginHelper.getUserId());
|
||||
start.setContentJson(bo.getContentJson());
|
||||
|
||||
Long instId = flowInstanceService.startInstance(start);
|
||||
// 更新状态为流转中
|
||||
updateStatus(add.getBizId(), "running");
|
||||
bean.setInstId(instId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user