You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
133 lines
7.4 KiB
Java
133 lines
7.4 KiB
Java
package com.yau.digitalrmb.training.application;
|
|
|
|
import lombok.AllArgsConstructor;
|
|
import lombok.Getter;
|
|
import org.springframework.jdbc.core.JdbcTemplate;
|
|
import org.springframework.stereotype.Service;
|
|
|
|
import java.time.Instant;
|
|
import java.util.ArrayList;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
@Service
|
|
public class TrainingTaskProgressService {
|
|
private static final String GENERATION = "PBOC_CURRENCY_GENERATION";
|
|
private static final String ISSUANCE = "PBOC_CURRENCY_ISSUANCE";
|
|
private static final String WALLET = "WALLET_OPENING";
|
|
private static final String EXCHANGE = "CURRENCY_EXCHANGE";
|
|
private static final String PAYMENT = "CURRENCY_PAYMENT";
|
|
|
|
private final JdbcTemplate jdbc;
|
|
private final Map<String, ModuleDefinition> definitions;
|
|
|
|
public TrainingTaskProgressService(JdbcTemplate jdbc) {
|
|
this.jdbc = jdbc;
|
|
this.definitions = definitions();
|
|
}
|
|
|
|
public List<TrainingTaskView> all(String userId) {
|
|
List<TrainingTaskView> result = new ArrayList<>();
|
|
for (String moduleCode : definitions.keySet()) result.add(one(userId, moduleCode));
|
|
return result;
|
|
}
|
|
|
|
public TrainingTaskView one(String userId, String moduleCode) {
|
|
ModuleDefinition module = definitions.get(moduleCode);
|
|
if (module == null) throw new IllegalArgumentException("不支持的实训模块:" + moduleCode);
|
|
List<String> completed = jdbc.queryForList("SELECT step_code FROM training_task_step_progress WHERE user_id = ? AND module_code = ?",
|
|
String.class, userId, moduleCode);
|
|
return view(module, completed);
|
|
}
|
|
|
|
/** 真实业务步骤成功后调用;同步补齐此前步骤,避免历史业务数据导致进度断层。 */
|
|
public void completeThrough(String userId, String moduleCode, String stepCode) {
|
|
ModuleDefinition module = definitions.get(moduleCode);
|
|
if (module == null || module.unavailable) return;
|
|
int index = module.indexOf(stepCode);
|
|
if (index < 0) return;
|
|
Instant now = Instant.now();
|
|
for (int i = 0; i <= index; i++) {
|
|
String currentStep = module.steps.get(i).code;
|
|
jdbc.update("INSERT INTO training_task_step_progress (user_id, module_code, step_code, completed_at) VALUES (?, ?, ?, ?) "
|
|
+ "ON DUPLICATE KEY UPDATE completed_at = completed_at",
|
|
userId, moduleCode, currentStep, now);
|
|
}
|
|
}
|
|
|
|
public void reset(String userId, String moduleCode) {
|
|
jdbc.update("DELETE FROM training_task_step_progress WHERE user_id = ? AND module_code = ?", userId, moduleCode);
|
|
}
|
|
|
|
private TrainingTaskView view(ModuleDefinition module, List<String> completed) {
|
|
List<TrainingStepView> steps = new ArrayList<>();
|
|
boolean prefixCompleted = true;
|
|
int completedCount = 0;
|
|
String currentStepCode = null;
|
|
for (StepDefinition step : module.steps) {
|
|
boolean done = prefixCompleted && completed.contains(step.code);
|
|
String status;
|
|
boolean actionAvailable = false;
|
|
if (done) {
|
|
status = "COMPLETED";
|
|
completedCount++;
|
|
} else if (module.unavailable && completedCount == 0) {
|
|
status = "NOT_STARTED";
|
|
prefixCompleted = false;
|
|
} else if (prefixCompleted) {
|
|
status = "CURRENT";
|
|
actionAvailable = true;
|
|
currentStepCode = step.code;
|
|
prefixCompleted = false;
|
|
} else {
|
|
status = "LOCKED";
|
|
}
|
|
steps.add(new TrainingStepView(step.code, step.name, step.sortNo, status, actionAvailable));
|
|
}
|
|
String status = completedCount == module.steps.size() ? "COMPLETED" : completedCount == 0 ? "NOT_STARTED" : "IN_PROGRESS";
|
|
return new TrainingTaskView(module.code, module.name, status, module.steps.size(), completedCount, currentStepCode,
|
|
module.unavailable, module.unavailableReason, steps);
|
|
}
|
|
|
|
private Map<String, ModuleDefinition> definitions() {
|
|
Map<String, ModuleDefinition> result = new LinkedHashMap<>();
|
|
result.put(GENERATION, module(GENERATION, "货币生成", false, null,
|
|
"机构身份信息与密钥准备", "生成数字货币请求", "验证货币生成请求", "生成交易信息标识", "生成额度控制位请求", "验证额度控制位请求", "控制系统签名", "生成额度控制位", "生成标准面额币串"));
|
|
result.put(ISSUANCE, module(ISSUANCE, "货币发行", false, null,
|
|
"查看货币需求", "生成发行申请计划", "发行计划数字签名", "发送标准报文", "中央银行验证与业务核查", "准备金通知与ACS扣减", "发行并确权数字货币"));
|
|
result.put(WALLET, module(WALLET, "开立数字钱包", true, "钱包开立真实业务接口尚未实现",
|
|
"开立数字钱包"));
|
|
result.put(EXCHANGE, module(EXCHANGE, "货币兑换", false, null,
|
|
"确认银行卡、钱包和商业银行库存", "生成取币请求报文", "钱包私钥签名", "商业银行验签并扣款", "央行确认币串权属"));
|
|
result.put(PAYMENT, module(PAYMENT, "数字货币支付", false, null,
|
|
"初始化付款方和收款方钱包", "签名支付请求", "付款行预处理", "中央银行结算", "收款行入账", "生成支付回执与到账通知"));
|
|
return Collections.unmodifiableMap(result);
|
|
}
|
|
|
|
private ModuleDefinition module(String code, String name, boolean unavailable, String reason, String... stepNames) {
|
|
List<StepDefinition> steps = new ArrayList<>();
|
|
for (int i = 0; i < stepNames.length; i++) steps.add(new StepDefinition(String.format("%02d", i + 1), stepNames[i], (i + 1) * 10));
|
|
return new ModuleDefinition(code, name, unavailable, reason, steps);
|
|
}
|
|
|
|
@Getter @AllArgsConstructor
|
|
public static class TrainingTaskView {
|
|
private final String moduleCode; private final String moduleName; private final String status;
|
|
private final int totalSteps; private final int completedSteps; private final String currentStepCode;
|
|
private final boolean actionUnavailable; private final String unavailableReason; private final List<TrainingStepView> steps;
|
|
}
|
|
@Getter @AllArgsConstructor
|
|
public static class TrainingStepView {
|
|
private final String stepCode; private final String stepName; private final int sortNo; private final String status; private final boolean actionAvailable;
|
|
}
|
|
private static class ModuleDefinition {
|
|
private final String code, name; private final boolean unavailable; private final String unavailableReason; private final List<StepDefinition> steps;
|
|
private ModuleDefinition(String code, String name, boolean unavailable, String unavailableReason, List<StepDefinition> steps) { this.code = code; this.name = name; this.unavailable = unavailable; this.unavailableReason = unavailableReason; this.steps = steps; }
|
|
private int indexOf(String code) { for (int i = 0; i < steps.size(); i++) if (steps.get(i).code.equals(code)) return i; return -1; }
|
|
}
|
|
private static class StepDefinition { private final String code, name; private final int sortNo; private StepDefinition(String code, String name, int sortNo) { this.code = code; this.name = name; this.sortNo = sortNo; } }
|
|
}
|