提案导出
This commit is contained in:
+33
-31
@@ -82,16 +82,7 @@ import java.util.stream.Collectors;
|
||||
@IocBean(args = {"refer:dao"})
|
||||
public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> implements ProposalCommonService {
|
||||
|
||||
/** 确定立案提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE = "proposal_confirm_filing";
|
||||
|
||||
/** 工作建议提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_SUGGESTION_TEMPLATE_CODE = "proposal_suggestion";
|
||||
|
||||
/** 不予立案提案的 Word 模板编码。 */
|
||||
private static final String PROPOSAL_NOT_TEMPLATE_CODE = "proposal_not";
|
||||
|
||||
/** 历史提案立案结果为空或无法识别时使用的原 Word 模板编码。 */
|
||||
/** 所有立案结果统一使用重庆工贸提案征集表模板。 */
|
||||
private static final String PROPOSAL_DEFAULT_TEMPLATE_CODE = "proposal";
|
||||
|
||||
/** PC端提案列表页面的排序字段白名单,页面代码由对应Controller固定传入。 */
|
||||
@@ -1367,6 +1358,11 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
execute(sql);
|
||||
NutMap docData = (NutMap) sql.getResult();
|
||||
|
||||
// 提案可能已被删除,避免在读取模板字段时产生空指针。
|
||||
if (docData == null) {
|
||||
throw new BaseException("提案信息不存在");
|
||||
}
|
||||
|
||||
//处理下富文本
|
||||
String brief = docData.getString("brief");
|
||||
String measures = docData.getString("measures");
|
||||
@@ -1381,12 +1377,23 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
ProcessInstance processInstance = dao().fetch(ProcessInstance.class, Cnd.where(ProcessInstance::getBusinessNo, "=", id));
|
||||
|
||||
List<ProcessTaskVO> doneTaskVos = new ArrayList<>();
|
||||
List<ProcessTask> doneTaskList = flowEngine.processTaskService().getDoneTaskList(processInstance.getId(), null);
|
||||
for (ProcessTask doneTask : doneTaskList) {
|
||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(doneTask.getId());
|
||||
doneTaskVos.add(taskVO);
|
||||
// 尚未启动或缺少 WF 实例的提案仍导出基础信息,附议和审批栏保持为空。
|
||||
if (processInstance != null) {
|
||||
List<ProcessTask> doneTaskList = flowEngine.processTaskService().getDoneTaskList(processInstance.getId(), null);
|
||||
for (ProcessTask doneTask : doneTaskList) {
|
||||
ProcessTaskVO taskVO = flowEngine.processTaskService().findById(doneTask.getId());
|
||||
if (taskVO != null && taskVO.getExt() != null) {
|
||||
doneTaskVos.add(taskVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 附议人单元格仅展示已完成附议任务中的姓名,多人以顿号分隔并去重。
|
||||
docData.put("secondNames", doneTaskVos.stream()
|
||||
.filter(task -> "second".equals(task.getTaskName()))
|
||||
.map(task -> task.getTaskFormData().getStr("userName"))
|
||||
.filter(StrUtil::isNotBlank).distinct().collect(Collectors.joining("、")));
|
||||
|
||||
// 按任务节点分组
|
||||
Map<String, List<ProcessTaskVO>> taskGroups = doneTaskVos.stream()
|
||||
.filter(Objects::nonNull)
|
||||
@@ -1394,6 +1401,17 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
docData.putAll(taskGroups);
|
||||
putProposalExportTaskAliases(id, taskGroups, docData);
|
||||
|
||||
// 中文区块名称保持与现有模板一致,实际审核记录按 WF 节点编码匹配。
|
||||
// 区块内继续读取 taskFormData 的意见、姓名和日期;无记录时写入空列表,避免同名节点误填。
|
||||
Map<String, String> approvalTemplateNodes = Map.of(
|
||||
"分工会主席审批", "delegation",
|
||||
"校工会主席审批", "schoolUnionChairApproval",
|
||||
"分管校领导审批", "school_leader");
|
||||
approvalTemplateNodes.forEach((templateKey, taskName) -> docData.put(templateKey, doneTaskVos.stream()
|
||||
.filter(task -> taskName.equals(task.getTaskName()))
|
||||
.sorted(Comparator.comparing(ProcessTaskVO::getFinishTime, Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.collect(Collectors.toList())));
|
||||
|
||||
// 提案附议
|
||||
List<NutMap> secondInfos = new ArrayList<>();
|
||||
List<ProcessTaskVO> secondTaskVos = taskGroups.get("提案附议");
|
||||
@@ -1475,29 +1493,13 @@ public class ProposalCommonServiceImpl extends BaseServiceImpl<ProposalInfo> imp
|
||||
docData.put("secondedList", secondInfos);
|
||||
docData.put("delegationAuditList", delegationAuditList);
|
||||
|
||||
String templateCode = getProposalTemplateCode(docData.getString("caseFilingResult"));
|
||||
try {
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(templateCode), config).render(docData).writeAndClose(byteArrayOutputStream);
|
||||
XWPFTemplate.compile(sysOfficeTemplateUtil.getTemplate(PROPOSAL_DEFAULT_TEMPLATE_CODE), config).render(docData).writeAndClose(byteArrayOutputStream);
|
||||
} catch (IOException e) {
|
||||
log.error("提案导出失败{},提案id:{}", e.getMessage(), id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据立案结果选择数据库办公模板编码。
|
||||
*
|
||||
* @param caseFilingResult 立案结果字典编码:CONFIRM_FILING、SUGGESTION 或 NOT
|
||||
* @return 对应的 Word 模板编码;历史空值或未知编码返回 proposal
|
||||
*/
|
||||
private String getProposalTemplateCode(String caseFilingResult) {
|
||||
return switch (StrUtil.nullToEmpty(caseFilingResult)) {
|
||||
case "CONFIRM_FILING" -> PROPOSAL_CONFIRM_FILING_TEMPLATE_CODE;
|
||||
case "SUGGESTION" -> PROPOSAL_SUGGESTION_TEMPLATE_CODE;
|
||||
case "NOT" -> PROPOSAL_NOT_TEMPLATE_CODE;
|
||||
default -> PROPOSAL_DEFAULT_TEMPLATE_CODE;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将现行工作流节点映射到历史提案表模板使用的区块名称,并按主协办单位拆分办理答复。
|
||||
* 模板仍使用旧节点名称时,避免已完成的意见和答复因键名不一致而无法渲染。
|
||||
|
||||
@@ -1,17 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<configuration scan="false" scanPeriod="60000" debug="false">
|
||||
|
||||
<!-- 定义日志文件的存储路径 -->
|
||||
<!-- 日志存储路径 -->
|
||||
<property name="LOG_HOME" value="./logs"/>
|
||||
|
||||
<!-- 控制台输出配置 -->
|
||||
<!-- 控制台输出 -->
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<!-- INFO级别日志文件配置 -->
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# 全文输出日志(一个文件存储)start #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
<!-- 所有级别日志写入同一个文件 -->
|
||||
<appender name="ALL_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/app.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/app-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- 框架日志级别(按需调整) -->
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="org.quartz" level="INFO"/>
|
||||
<logger name="org.nutz" level="DEBUG"/>
|
||||
|
||||
<!-- root logger:DEBUG 级别,输出到控制台和全量文件 -->
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="ALL_FILE"/>
|
||||
</root>
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# 全文输出日志(一个文件存储)end #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
|
||||
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# debug、info、error分文件输出 start #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
<!-- DEBUG级别日志文件配置 -->
|
||||
<!--<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/debug.log</file>
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.LevelFilter">
|
||||
<level>DEBUG</level>
|
||||
<onMatch>ACCEPT</onMatch>
|
||||
<onMismatch>DENY</onMismatch>
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/debug-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!– INFO级别日志文件配置 –>
|
||||
<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/info.log</file>
|
||||
<encoder>
|
||||
@@ -24,11 +92,11 @@
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/info-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<!-- ERROR级别日志文件配置 -->
|
||||
<!– ERROR级别日志文件配置 –>
|
||||
<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<file>${LOG_HOME}/error.log</file>
|
||||
<encoder>
|
||||
@@ -41,19 +109,31 @@
|
||||
</filter>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<fileNamePattern>${LOG_HOME}/error-%d{yyyy-MM-dd}.log</fileNamePattern>
|
||||
<maxHistory>30</maxHistory>
|
||||
<maxHistory>300</maxHistory>
|
||||
</rollingPolicy>
|
||||
</appender>
|
||||
|
||||
<logger name="java" additivity="false" />
|
||||
<!– 框架日志级别 –>
|
||||
<!– <logger name="java" additivity="false" />–>
|
||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||
<logger name="org.quartz" level="INFO"/>
|
||||
<logger name="org.nutz" level="DEBUG"/>
|
||||
|
||||
<!-- 日志级别和appender的关联 -->
|
||||
<!– 日志级别和appender的关联 –>
|
||||
<root level="DEBUG">
|
||||
<appender-ref ref="STDOUT"/>
|
||||
<appender-ref ref="DEBUG_FILE"/>
|
||||
<appender-ref ref="INFO_FILE"/>
|
||||
<appender-ref ref="ERROR_FILE"/>
|
||||
</root>
|
||||
</root>-->
|
||||
|
||||
<!--
|
||||
#################################################################################
|
||||
# #
|
||||
# debug、info、error分文件输出 end #
|
||||
# #
|
||||
#################################################################################
|
||||
-->
|
||||
|
||||
</configuration>
|
||||
|
||||
|
||||
@@ -88,7 +88,8 @@ layout("/layouts/platform.html"){
|
||||
</template>
|
||||
|
||||
<template #edit>
|
||||
<el-form :model="formData" :rules="welfareFormRules" label-width="150px" ref="form" v-loading="formLoading">
|
||||
<el-form :model="formData" :rules="welfareFormRules" :validate-on-rule-change="false"
|
||||
@submit.native.prevent label-width="150px" ref="form" v-loading="formLoading">
|
||||
<el-form-item label="沿用往期福利" v-if="!formData.id">
|
||||
<el-select clearable filterable placeholder="请选择往期福利" style="width: 100%"
|
||||
v-model="reuseProjectId" @change="reuseHistoryProject">
|
||||
@@ -294,10 +295,12 @@ layout("/layouts/platform.html"){
|
||||
welfareFormRules() {
|
||||
// 慰问金只要求项目名称和单个发放时间,其他发放形式沿用原有校验。
|
||||
const requiredForOtherMode = this.formData.provideMode !== 99
|
||||
// 慰问金在提交时统一校验,输入项目名称或切换表单项时不提前提示。
|
||||
const requiredTrigger = requiredForOtherMode ? ["blur", "change"] : "submit"
|
||||
return {
|
||||
name: [{ required: true, message: "必填", trigger: ["blur", "change"] }],
|
||||
name: [{ required: true, message: "必填", trigger: requiredTrigger }],
|
||||
festival: [{ required: requiredForOtherMode, message: "必选", trigger: ["blur", "change"] }],
|
||||
provideTime: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
|
||||
provideTime: [{ required: true, message: "必选", trigger: requiredTrigger }],
|
||||
choiceTime: [{ required: requiredForOtherMode, message: "必选", trigger: ["blur", "change"] }],
|
||||
provideAddress: [{ required: requiredForOtherMode, message: "必选", trigger: ["blur", "change"] }],
|
||||
provideMode: [{ required: true, message: "必选", trigger: ["blur", "change"] }],
|
||||
@@ -410,6 +413,9 @@ layout("/layouts/platform.html"){
|
||||
this.$set(this, "reuseProjectId", null)
|
||||
if (this.$refs.form) this.$refs.form.resetFields()
|
||||
this.$set(this, "formData", {
|
||||
name: "",
|
||||
choiceTime: [],
|
||||
provideTime: null,
|
||||
provideMode: 99,
|
||||
isPushHome: false,
|
||||
signMode: 4,
|
||||
|
||||
Reference in New Issue
Block a user