feat: 会议材料上传/发票OCR识别/用户管理增强 + 日志降噪 + 薪亿通接口规范

- 会议/劳务材料支持直接上传与提交审核 (BizMeetingMaterial 等)
- 发票 OCR 识别增强 (InvoiceOcrService)
- 现场照片/证书批量导入覆盖式回填 (ExcelUtil/AttendeeImportVo/CameraQrUpload)
- 用户管理增强、超级管理员校验与权限拒绝处理 (SuperManagerChecker/AccessDeniedHandlerImpl)
- 日志级别调整为 info/warn (生产降噪)
- 新增薪亿通·个人票税接口规范文档 (自然人开票服务分册 + 轻量化对接分册)
- .gitignore 排除 key.txt/*.rdb/*.key/tmp/opt 等敏感与本地文件

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
2026-11-12 01:13:17 +00:00
co-authored by Claude Code
parent 44d4920777
commit 3f587fbd9f
39 changed files with 1544 additions and 192 deletions
@@ -58,7 +58,9 @@ public class SysUser extends BaseEntity
/** 删除标志(0代表存在 2代表删除) */
private String delFlag;
/** 账号类型 (MAIN=主账号 / SUB=子账号) */
/** 账号类型 (MAIN=主账号 / SUB=子账号, null 视为 SUB). 按角色语义复用:
* executor/sponsor: MAIN=机构主账号 / SUB=机构子账号(挂 parent_user_id);
* manager: MAIN=全局管理员(可见全量) / SUB 或 null=普通合规员(只看本人创建, parent_user_id 恒 NULL) */
@Excel(name = "账号类型")
private String accountType;
@@ -70,7 +70,7 @@ public class HttpUtils
try
{
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
log.info("sendGet - {}", urlNameString);
log.debug("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
// 连接/读超时: 防止外部接口不可达时无限挂起 (后台子任务会占死单线程调度器)
@@ -86,7 +86,7 @@ public class HttpUtils
{
result.append(line);
}
log.info("recv - {}", result);
log.info("recv(len={}) - {}", result.length(), result.substring(0, Math.min(result.length(), 200)));
}
catch (ConnectException e)
{
@@ -148,7 +148,7 @@ public class HttpUtils
StringBuilder result = new StringBuilder();
try
{
log.info("sendPost - {}", url);
log.debug("sendPost - {}", url);
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
@@ -167,7 +167,7 @@ public class HttpUtils
{
result.append(line);
}
log.info("recv - {}", result);
log.info("recv(len={}) - {}", result.length(), result.substring(0, Math.min(result.length(), 200)));
}
catch (ConnectException e)
{
@@ -217,7 +217,7 @@ public class HttpUtils
String urlNameString = url + "?" + param;
try
{
log.info("sendSSLPost - {}", urlNameString);
log.debug("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
URL console = new URL(urlNameString);
@@ -243,7 +243,7 @@ public class HttpUtils
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
}
}
log.info("recv - {}", result);
log.info("recv(len={}) - {}", result.length(), result.substring(0, Math.min(result.length(), 200)));
conn.disconnect();
br.close();
}
@@ -1,5 +1,6 @@
package com.ruoyi.common.utils.poi;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -746,6 +747,36 @@ public class ExcelUtil<T>
exportExcel(response);
}
/**
* 生成导入模板 Excel 的字节 (仅表头, 无数据行), 用于打进 zip 模板.
*
* @param sheetName 工作表的名称
* @param title 标题
* @return Excel 字节
*/
public byte[] importTemplateExcelBytes(String sheetName, String title)
{
ByteArrayOutputStream out = null;
try
{
this.init(null, sheetName, title, Type.IMPORT);
writeSheet();
out = new ByteArrayOutputStream();
wb.write(out);
return out.toByteArray();
}
catch (Exception e)
{
log.error("导出Excel异常{}", e.getMessage());
throw new UtilException("导出Excel失败,请联系网站管理员!");
}
finally
{
IOUtils.closeQuietly(wb);
IOUtils.closeQuietly(out);
}
}
/**
* 对list数据源将其里面的数据导入到excel表单
*