diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java index c9b62024..5b9318a8 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/constant/HcsSyncConstant.java @@ -180,6 +180,16 @@ public final class HcsSyncConstant { */ public static final String PUSH_TASK_LOCK_KEY_PREFIX = "blade:third:hcs:push:task:lock:"; + /** + * 即时推送单条锁 key 前缀(审批通过即时推送防与扫描任务并发双推,完整 key = 前缀 + 业务类型 + ":" + 单据ID) + */ + public static final String PUSH_SINGLE_LOCK_KEY_PREFIX = "blade:third:hcs:push:lock:"; + + /** + * 即时推送单条锁 TTL(秒):大于单条推送预期时长,异常残留锁自动过期后由扫描兜底 + */ + public static final long PUSH_SINGLE_LOCK_TTL_SECONDS = 120L; + private HcsSyncConstant() { } } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java index d82c820f..cfcfe4bf 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/mk/MkProcessBizHandlers.java @@ -17,6 +17,7 @@ import org.springblade.transport.service.IPreSettlementService; import org.springblade.transport.constant.HcsSyncConstant; import org.springblade.transport.service.IProjectApplyService; import org.springblade.transport.service.IWaybillService; +import org.springblade.transport.support.hcs.HcsImmediatePushSupport; import org.springframework.stereotype.Component; import java.time.LocalDateTime; @@ -66,6 +67,7 @@ public final class MkProcessBizHandlers { @RequiredArgsConstructor public static class ProjectHandler implements IMkProcessBizHandler { private final IProjectApplyService service; + private final HcsImmediatePushSupport hcsImmediatePushSupport; @Override public String bizType() { @@ -113,9 +115,13 @@ public final class MkProcessBizHandlers { entity.setCurrentNode("审核通过"); entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统")); entity.setApprovedTime(LocalDateTime.now()); - // HCS 推送零埋点:MK 审批回调仅置待同步状态,与 /approve 入口收敛于同一权威状态(ADR-0001) + // HCS 推送:审批通过置待同步状态,更新成功后即时推送,扫描任务保留兜底(ADR-0001 修订,前端接入设计 §6) entity.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_UNSYNCED); - return service.updateById(entity); + boolean updated = service.updateById(entity); + if (updated) { + hcsImmediatePushSupport.pushProjectAfterCommit(id); + } + return updated; } @Override @@ -138,6 +144,7 @@ public final class MkProcessBizHandlers { @RequiredArgsConstructor public static class ContractHandler implements IMkProcessBizHandler { private final IContractManageService service; + private final HcsImmediatePushSupport hcsImmediatePushSupport; @Override public String bizType() { @@ -183,9 +190,13 @@ public final class MkProcessBizHandlers { entity.setApprovalStatus(change ? "change_approved" : "approved"); entity.setCurrentNode("审核通过"); entity.setCurrentProcessor(MkProcessNodeHelper.text(processorName, "系统")); - // HCS 推送零埋点:MK 审批回调仅置待同步状态,与 /approve 入口收敛于同一权威状态(ADR-0001) + // HCS 推送:审批通过置待同步状态,更新成功后即时推送,扫描任务保留兜底(ADR-0001 修订,前端接入设计 §6) entity.setHcsSyncStatus(HcsSyncConstant.HCS_STATUS_UNSYNCED); - return service.updateById(entity); + boolean updated = service.updateById(entity); + if (updated) { + hcsImmediatePushSupport.pushContractAfterCommit(id); + } + return updated; } @Override diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java index 41cc4285..cddc6b68 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ContractManageServiceImpl.java @@ -44,6 +44,7 @@ import org.springblade.transport.pojo.entity.HcsContractExeStage; import org.springblade.transport.pojo.vo.ContractManageVO; import org.springblade.transport.service.IContractManageService; import org.springblade.transport.support.TransportBusinessSupport; +import org.springblade.transport.support.hcs.HcsImmediatePushSupport; import org.springblade.transport.wrapper.ContractManageWrapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -72,6 +73,7 @@ import java.util.Set; public class ContractManageServiceImpl extends BaseServiceImpl implements IContractManageService { private final HcsContractExeStageMapper hcsContractExeStageMapper; + private final HcsImmediatePushSupport hcsImmediatePushSupport; private static final String STAGE_DRAFT = "draft"; private static final String STAGE_TEMPORARY = "temporary"; @@ -223,13 +225,14 @@ public class ContractManageServiceImpl extends BaseServiceImpllambdaUpdate() .eq(HcsContractExeStage::getContractId, contractManage.getId()) .isNull(HcsContractExeStage::getHcsStageFdId) .set(HcsContractExeStage::getRowOp, "add")); + hcsImmediatePushSupport.pushContractAfterCommit(id); return updateById(contractManage); } diff --git a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ProjectApplyServiceImpl.java b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ProjectApplyServiceImpl.java index f55c6f41..066abafa 100644 --- a/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ProjectApplyServiceImpl.java +++ b/blade-service/blade-transport/src/main/java/org/springblade/transport/service/impl/ProjectApplyServiceImpl.java @@ -49,6 +49,7 @@ import org.springblade.transport.pojo.entity.TemporaryCreditLimit; import org.springblade.transport.pojo.vo.ProjectApplyVO; import org.springblade.transport.service.IProjectApplyService; import org.springblade.transport.support.TransportBusinessSupport; +import org.springblade.transport.support.hcs.HcsImmediatePushSupport; import org.springblade.transport.wrapper.ProjectApplyWrapper; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -95,6 +96,7 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl selectProjectApplyPage(IPage page, ProjectApplyVO projectApply) { @@ -212,8 +214,9 @@ public class ProjectApplyServiceImpl extends BaseServiceImpl + * Use of this software is governed by the Commercial License Agreement + * obtained after purchasing a license from BladeX. + *

+ * 1. This software is for development use only under a valid license + * from BladeX. + *

+ * 2. Redistribution of this software's source code to any third party + * without a commercial license is strictly prohibited. + *

+ * 3. Licensees may copyright their own code but cannot use segments + * from this software for such purposes. Copyright of this software + * remains with BladeX. + *

+ * Using this software signifies agreement to this License, and the software + * must not be used for illegal purposes. + *

+ * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is + * not liable for any claims arising from secondary or illegal development. + *

+ * Author: Chill Zhuang (bladejava@qq.com) + */ +package org.springblade.transport.support.hcs; + +import jakarta.annotation.PreDestroy; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springblade.core.redis.cache.BladeRedis; +import org.springblade.transport.constant.HcsSyncConstant; +import org.springblade.transport.mapper.ContractManageMapper; +import org.springblade.transport.mapper.ProjectApplyMapper; +import org.springblade.transport.pojo.entity.ContractManage; +import org.springblade.transport.pojo.entity.ProjectApply; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import java.time.Duration; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * HCS 审批通过即时推送(前端接入设计 §6,2026-10-10 增补) + *

+ * 项目立项(C102)/合同(C103)审批通过(含变更通过)事务提交后立即异步触发单条推送,不再等待扫描周期; + * 执行体复用 {@link HcsProjectSyncSupport#repushProject(Long)} / {@link HcsContractSyncSupport#repushContract(Long)} + * (已含审批状态校验、失败 markFailed、高风险特批挂起判断),失败仅留痕,由 HcsPushTask 扫描兜底补偿 + * (ADR-0001 修订:审批代码埋点为一行触发调用,推送逻辑仍收敛在 hcs support 包)。 + *

+ * 触发模型:审批事务内调用则注册 afterCommit 回调(事务回滚不推送),无活动事务(MK 回调单条更新自动提交)直接提交; + * 自建 2 线程 daemon 池(工程未启用 @EnableAsync),HCS 推送可达 20s+ 不阻塞审批响应; + * Redis 单条锁防与扫描任务并发双推(TTL 120s,持有值比对释放,照 HcsPushTask 惯例), + * 极端双推由 HCS 侧判重/更新幂等吸收。与扫描任务同线程模型(无租户上下文),行为一致。 + * + * @author Chill + */ +@Slf4j +@Component +@RequiredArgsConstructor +public class HcsImmediatePushSupport { + + /** + * 审批通过状态集合(与 HcsPushTask.APPROVED_STATUSES 一致,含变更通过) + */ + private static final List APPROVED_STATUSES = List.of("approved", "change_approved"); + + /** + * 推送线程编号(线程名 hcs-immediate-push-N 便于日志定位) + */ + private static final AtomicInteger THREAD_COUNTER = new AtomicInteger(1); + + private final HcsProjectSyncSupport hcsProjectSyncSupport; + private final HcsContractSyncSupport hcsContractSyncSupport; + private final ProjectApplyMapper projectApplyMapper; + private final ContractManageMapper contractManageMapper; + private final BladeRedis bladeRedis; + + /** + * 即时推送总开关(thirdParty.hcs.push.immediate-enabled,默认关闭灰度打开;关闭时完全回落扫描链路) + */ + @Value("${thirdParty.hcs.push.immediate-enabled:false}") + private boolean immediateEnabled; + + /** + * 推送线程池:2 线程 daemon,即时推送与定时扫描互不影响 + */ + private final ExecutorService pushExecutor = Executors.newFixedThreadPool(2, task -> { + Thread thread = new Thread(task, "hcs-immediate-push-" + THREAD_COUNTER.getAndIncrement()); + thread.setDaemon(true); + return thread; + }); + + /** + * 项目立项(C102)审批通过后即时推送:须在审批事务内调用(afterCommit 触发) + * + * @param id 项目立项单ID + */ + public void pushProjectAfterCommit(Long id) { + this.submitAfterCommit(HcsSyncConstant.BIZ_TYPE_PROJECT, id, () -> this.pushProjectNow(id)); + } + + /** + * 合同(C103)审批通过后即时推送:须在审批事务内调用(afterCommit 触发) + * + * @param id 合同单ID + */ + public void pushContractAfterCommit(Long id) { + this.submitAfterCommit(HcsSyncConstant.BIZ_TYPE_CONTRACT, id, () -> this.pushContractNow(id)); + } + + /** + * 开关校验后注册提交时机:有活动事务注册 afterCommit 回调(回滚不推送),无事务(MK 回调单条更新自动提交)直接异步 + */ + private void submitAfterCommit(String bizType, Long id, Runnable pushAction) { + if (!immediateEnabled) { + return; + } + Runnable pushTask = () -> this.pushWithLock(bizType, id, pushAction); + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + pushExecutor.execute(pushTask); + } + }); + } else { + pushExecutor.execute(pushTask); + } + } + + /** + * 单条锁防并发双推:抢不到即放弃(扫描兜底),持有值比对后释放 + */ + private void pushWithLock(String bizType, Long id, Runnable pushAction) { + String lockKey = HcsSyncConstant.PUSH_SINGLE_LOCK_KEY_PREFIX + bizType + ":" + id; + String lockHolder = UUID.randomUUID().toString(); + Boolean locked = bladeRedis.getValueOps() + .setIfAbsent(lockKey, lockHolder, Duration.ofSeconds(HcsSyncConstant.PUSH_SINGLE_LOCK_TTL_SECONDS)); + if (!Boolean.TRUE.equals(locked)) { + log.info("HCS即时推送跳过(其他线程推送中):bizType={},id={}", bizType, id); + return; + } + try { + pushAction.run(); + } finally { + if (lockHolder.equals(bladeRedis.get(lockKey))) { + bladeRedis.del(lockKey); + } + } + } + + /** + * 项目立项推送执行体:非审批通过/已同步短路跳过,失败已由 Support markFailed,仅留痕交扫描补偿 + */ + private void pushProjectNow(Long id) { + try { + ProjectApply projectApply = projectApplyMapper.selectById(id); + if (projectApply == null || !APPROVED_STATUSES.contains(projectApply.getApprovalStatus()) + || HcsSyncConstant.HCS_STATUS_SYNCED.equals(projectApply.getHcsSyncStatus())) { + return; + } + hcsProjectSyncSupport.repushProject(id); + } catch (Exception exception) { + log.error("HCS项目立项即时推送失败(扫描任务将兜底补偿):id={},{}", id, exception.getMessage(), exception); + } + } + + /** + * 合同推送执行体:非审批通过/已同步/特批挂起中短路跳过,失败已由 Support markFailed,仅留痕交扫描补偿 + */ + private void pushContractNow(Long id) { + try { + ContractManage contractManage = contractManageMapper.selectById(id); + if (contractManage == null || !APPROVED_STATUSES.contains(contractManage.getApprovalStatus()) + || HcsSyncConstant.HCS_STATUS_SYNCED.equals(contractManage.getHcsSyncStatus())) { + return; + } + if (List.of(HcsSyncConstant.SPEC_STATUS_NEED, HcsSyncConstant.SPEC_STATUS_PROCESSING).contains(contractManage.getHcsSpecStatus())) { + log.info("HCS合同即时推送跳过(特批挂起中):id={},hcsSpecStatus={}", id, contractManage.getHcsSpecStatus()); + return; + } + hcsContractSyncSupport.repushContract(id); + } catch (Exception exception) { + log.error("HCS合同即时推送失败(扫描任务将兜底补偿):id={},{}", id, exception.getMessage(), exception); + } + } + + @PreDestroy + public void shutdown() { + pushExecutor.shutdown(); + } +} diff --git a/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md b/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md index 7fb368f3..f166d009 100644 --- a/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md +++ b/doc/docs/hcs合同/2026-10-09-项目立项与合同HCS前端接入设计.md @@ -11,7 +11,7 @@ | # | 原则 | |---|---| | P1 | **前端不直连 HCS**。所有 C 系列接口由 tms-api 代理:`Authorization`/`Key-Auth` 静态双头只存在于服务端,浏览器不可见,也无跨域问题 | -| P2 | **自动推送不动**。C102-1/2、C103-1/11 仍走"审批通过 → 置 unsynced → 扫描任务推送"链路(零埋点,ADR-0001),前端只补**状态展示 + 手动重推 + 对账回查** | +| P2 | **自动推送保留扫描兜底**。C102-1/2、C103-1/11 走"审批通过 → 置 unsynced → 扫描任务推送"链路(ADR-0001);2026-10-10 增补**审批通过即时推送**(§6),扫描任务降级为兜底补偿。前端只补**状态展示 + 手动重推 + 对账回查** | | P3 | **附件主存储仍在 TMS OSS**。表单上传逻辑不改;HCS 转传由后端推送链路自动完成(HcsAttachmentSupport 已实现)。前端新增的是**手动转传**(特批材料、确定性上传)与**HCS 附件回下载** | | P4 | **前端结算币种/合同分类不改**。两个下拉继续用本地字典(`currency_type`/`contractCategory`),存量值与交互零变化;C103-12 币种、C103-7 分类只在后端推送侧映射(`currency-name-mapping`/`template-mapping`,已实现),前端无触点 | | P5 | UI 照**"同步金蝶"按钮模式**(参考 `customer-archive.vue`、`formal-settlement-table-panel.vue` 的 kingdeeSyncStatus 列 + 推送按钮),HCS 用 `hcsSyncStatus` 等同构字段 | @@ -110,11 +110,11 @@ POST /hcs/contract/spec-apply (body:{ contractId, attachments: [{fdId, 组装报文调 C103-8(报文模式预估照 C106-3:fd_contract_id=hcs_fd_id、fd_contract_no、 fd_doc_subject="合同特批-"+contractNo、特批附件 mechanisms.attachment 带 fdBindType=ADD) → 返回 data.fdId → hcs_spec_fd_id,状态置 processing;失败置 need 并记 hcs_spec_msg - → C103-8 v4 未含报文,联调前按上述预估实现并加 TODO 标注(§6-U1) + → C103-8 v4 未含报文,联调前按上述预估实现并加 TODO 标注(§7-U1) POST /hcs/callback/spec-result (B103 合规→TMS 回调接收端点) 公开端点(@PreAuth(AuthConstant.PERMIT_ALL) + 报文验签字段待合规方口径,先记录原文留痕) - body:{ 合同标识/特批流程fdId, 审批结果, 审批意见 } ← 字段名待 B103 报文(§6-U1) + body:{ 合同标识/特批流程fdId, 审批结果, 审批意见 } ← 字段名待 B103 报文(§7-U1) 处理:定位合同 → 回写 hcs_spec_status=approved/rejected + hcs_spec_msg → approved 时把合同 hcs_sync_status 重置 unsynced,由既有扫描任务自动走 C103-1(零新增链路) → B103 报文未到位前端点先落库留痕不置状态,联调时接线 @@ -241,11 +241,67 @@ export const applyContractSpec = data => | F1 基础 | `GET /hcs/master-data/template` + `@PreAuth`/菜单 SQL | `api/business/hcs.js`;管理端主数据页 | 无 | | F2 状态与推送 | 无(端点已有) | 两列表页:状态列/筛选 + 推送合规按钮 | F1(hcs.js) | | F3 对账与附件 | `/hcs/risk`、`/hcs/attachment/upload`、`/hcs/attachment/download` | 对账弹窗 + 合规附件下载 + 手动转传 + 附件行 `hcsFdId` | F2 | -| F4 特批 | 合同特批字段组 SQL;`POST /hcs/contract/spec-apply` + `POST /hcs/callback/spec-result`(B103);合同推送链路加 need 挂起判断 | 发起特批弹窗 + 特批状态标签 + 按钮联动 | C103-8/B103 报文(§6-U1,可先按预估模式实现联调替换) | +| F4 特批 | 合同特批字段组 SQL;`POST /hcs/contract/spec-apply` + `POST /hcs/callback/spec-result`(B103);合同推送链路加 need 挂起判断 | 发起特批弹窗 + 特批状态标签 + 按钮联动 | C103-8/B103 报文(§7-U1,可先按预估模式实现联调替换) | +| F5 即时推送(2026-10-10 增补,纯后端) | `HcsImmediatePushSupport` + 4 处审批入口触发(§6.3)+ 开关配置 | 无 | 无(复用既有 Support,扫描兜底保留) | --- -## 6. 未决事项 +## 6. 审批通过即时推送(2026-10-10 增补,后端链路增强) + +### 6.1 目标与原则 + +| # | 原则 | +|---|---| +| I1 | **秒级触达**:项目立项(C102-1/2)、合同(C103-1/11)审批通过(含变更通过)事务提交后立即异步推送,不再等扫描周期(原最长 ≤5 分钟) | +| I2 | **ADR-0001 修订**:审批代码埋点由"零"放宽为"一行触发调用"(仅传 id,不含任何推送逻辑);推送逻辑仍全部收敛在 hcs support 包,扫描任务保留为**兜底**(失败重试、批量补偿、停机窗口漏单) | +| I3 | **复用既有链路**:执行体直接调 `repushProject(id)` / `repushContract(id)`(已含 approved 校验、状态重置、失败 markFailed、高风险挂起判断),不新写报文与状态机 | + +### 6.2 新增组件:HcsImmediatePushSupport(仅 1 个类) + +位置 `org.springblade.transport.support.hcs`,职责只有一个:**事务提交后异步触发一次单条推送**。 + +```java +public void pushProjectAfterCommit(Long id) // 项目 C102 +public void pushContractAfterCommit(Long id) // 合同 C103 +``` + +执行模型: + +1. **afterCommit 触发**:审批方法在事务内调用本组件 → `TransactionSynchronizationManager.registerSynchronization` 注册 afterCommit 回调,审批事务回滚则不推送。MK 回调路径若未包事务(单条 updateById 自动提交)则直接提交异步,语义等价。 +2. **异步执行**:自建 2 线程 daemon 池(线程名 `hcs-immediate-push`,`@PreDestroy` 释放)。工程未启用 `@EnableAsync`,不为此新增全局配置;HCS 推送含风险校验+附件转传+起草可达 20s+,绝不能阻塞审批响应。 +3. **执行体**(与 HcsPushTask 同线程模型,无租户上下文,与定时扫描行为一致): + - 开关:`thirdParty.hcs.push.immediate-enabled`(默认 false,灰度打开) + - 短路:查库 `approvalStatus ∉ {approved, change_approved}` 或 `hcs_sync_status = synced` → 跳过(已被扫描/人工重推处理过) + - 单条锁:Redis `setIfAbsent("blade:third:hcs:push:lock:{bizType}:{id}", TTL 120s)`,抢不到直接放弃(扫描兜底),持有值比对后释放(照 HcsPushTask 惯例) + - 推送:`repushProject(id)` / `repushContract(id)`;异常仅 `log.error` 吞掉(Support 内部已 markFailed,扫描按 `hcs_retry_count < max-retry` 自动补偿,超限人工重推,D7 不变) + +### 6.3 触发点(4 处,各加 1 行) + +| 入口 | 位置 | 触发调用 | +|---|---|---| +| 本地审批 | `ProjectApplyServiceImpl.approve()`(事务内,含变更通过,现有置 unsynced 行之后) | `pushProjectAfterCommit(id)` | +| 本地审批 | `ContractManageServiceImpl.approve()`(事务内,含变更通过 + 履约行置 add,`updateById` 之后) | `pushContractAfterCommit(id)` | +| MK 回调 | `MkProcessBizHandlers.ProjectHandler.approveFromProcess()`(`updateById` 返回 true 后) | `pushProjectAfterCommit(id)` | +| MK 回调 | `MkProcessBizHandlers.ContractHandler.approveFromProcess()`(同上) | `pushContractAfterCommit(id)` | + +### 6.4 并发与失败语义 + +| 场景 | 语义 | +|---|---| +| 即时推送 vs 扫描任务并发 | 单条锁 + synced 短路 + HCS 侧判重(C102-3 / C103 判重、更新幂等)三重吸收;极端双推为更新语义,无脏数据 | +| 即时推送失败 | `markFailed` → 扫描下轮自动补偿 → 超限人工重推(与现状完全一致,零新增重试机制) | +| 高风险合同 | `pushContract` 既有 `hcs_spec_status ∈ {need, processing}` 挂起判断不变,即时推送同样被挂起,特批通过后恢复推送 | +| 开关关闭 / 组件异常 | 完全回落扫描链路,行为与现状一致 | + +### 6.5 配置 + +| 配置项 | 默认 | 说明 | +|---|---|---| +| `thirdParty.hcs.push.immediate-enabled` | false | 即时推送总开关,灰度打开;普通 `@Value` 重启生效即可(扫描兜底使风险可控,无需 @RefreshScope) | + +--- + +## 7. 未决事项 | # | 事项 | 影响 | 当前处理 | |---|---|---|---|