feat:文件上传的功能开发
parent
fc53367daa
commit
f19428560a
@ -0,0 +1,15 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.application;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Schema(description = "拼接工资发放申请原文结果")
|
||||||
|
public class SalaryConcatenateResult {
|
||||||
|
@Schema(description = "拼接原文(管道分隔)")
|
||||||
|
private final String concatenatedMessage;
|
||||||
|
|
||||||
|
public SalaryConcatenateResult(String concatenatedMessage) {
|
||||||
|
this.concatenatedMessage = concatenatedMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.application;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Schema(description = "输出JSON结果")
|
||||||
|
public class SalaryOutputResult {
|
||||||
|
@Schema(description = "输出JSON报文")
|
||||||
|
private final String outputJson;
|
||||||
|
|
||||||
|
public SalaryOutputResult(String outputJson) {
|
||||||
|
this.outputJson = outputJson;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,94 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.application;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.yau.digitalrmb.institutionidentity.infrastructure.StuModuleScoreDetailsEntity;
|
||||||
|
import com.yau.digitalrmb.institutionidentity.infrastructure.StuModuleScoreDetailsMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业发放数字人民币工资模块的成绩统计服务。
|
||||||
|
* 错误次数同步到平台统一成绩明细表。
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SalaryScoreService {
|
||||||
|
public static final String MODULE_NAME = "企业发放数字人民币工资";
|
||||||
|
private static final int MODULE_SERIAL_NUMBER = 6;
|
||||||
|
private static final double TOTAL_SCORE = 100.0;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StuModuleScoreDetailsMapper scoreDetailsMapper;
|
||||||
|
|
||||||
|
@Value("${salary.score.wrong-deduct:0.50}")
|
||||||
|
private BigDecimal wrongDeduct = new BigDecimal("0.50");
|
||||||
|
|
||||||
|
@Transactional(propagation = Propagation.REQUIRES_NEW)
|
||||||
|
public int recordError(String userId) {
|
||||||
|
if (userId == null || userId.trim().isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
StuModuleScoreDetailsEntity detail = getOrCreate(userId);
|
||||||
|
int accumulatedErrorCount = errorCount(detail.getCompletionStatus()) + 1;
|
||||||
|
detail.setCompletionStatus(String.valueOf(accumulatedErrorCount));
|
||||||
|
detail.setScoreProject(score(accumulatedErrorCount, progress(detail.getSchedule())));
|
||||||
|
scoreDetailsMapper.updateById(detail);
|
||||||
|
return accumulatedErrorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private StuModuleScoreDetailsEntity getOrCreate(String userId) {
|
||||||
|
StuModuleScoreDetailsEntity existing = scoreDetailsMapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<StuModuleScoreDetailsEntity>()
|
||||||
|
.eq(StuModuleScoreDetailsEntity::getUserId, userId)
|
||||||
|
.eq(StuModuleScoreDetailsEntity::getMoudule, MODULE_NAME)
|
||||||
|
.eq(StuModuleScoreDetailsEntity::getSerialNumber, MODULE_SERIAL_NUMBER)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
if (existing != null) {
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
StuModuleScoreDetailsEntity created = new StuModuleScoreDetailsEntity();
|
||||||
|
created.setId(UUID.randomUUID().toString());
|
||||||
|
created.setMoudule(MODULE_NAME);
|
||||||
|
created.setLearningProjects("实验实训");
|
||||||
|
created.setAssessmentItems("工资发放流程错误次数");
|
||||||
|
created.setScoringCriteria(wrongDeduct.stripTrailingZeros().toPlainString());
|
||||||
|
created.setCompletionStatus("0");
|
||||||
|
created.setScoreProject(0.0);
|
||||||
|
created.setUserId(userId);
|
||||||
|
created.setTotalScore(TOTAL_SCORE);
|
||||||
|
created.setSerialNumber(MODULE_SERIAL_NUMBER);
|
||||||
|
created.setSchedule(0.0);
|
||||||
|
scoreDetailsMapper.insert(created);
|
||||||
|
return created;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double score(int errorCount, double schedule) {
|
||||||
|
BigDecimal base = BigDecimal.valueOf(TOTAL_SCORE)
|
||||||
|
.subtract(wrongDeduct.multiply(BigDecimal.valueOf(Math.max(0, errorCount))))
|
||||||
|
.max(BigDecimal.ZERO);
|
||||||
|
return base.multiply(BigDecimal.valueOf(schedule))
|
||||||
|
.divide(BigDecimal.valueOf(TOTAL_SCORE), 2, RoundingMode.HALF_UP)
|
||||||
|
.doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private double progress(Double schedule) {
|
||||||
|
return schedule == null ? 0.0 : schedule;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int errorCount(String completionStatus) {
|
||||||
|
if (completionStatus == null || completionStatus.trim().isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Math.max(0, Integer.parseInt(completionStatus));
|
||||||
|
} catch (NumberFormatException exception) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.application;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Schema(description = "发送结果")
|
||||||
|
public class SalarySendResult {
|
||||||
|
@Schema(description = "状态:待审核")
|
||||||
|
private final String status;
|
||||||
|
@Schema(description = "发送时间")
|
||||||
|
private final String submitTime;
|
||||||
|
|
||||||
|
public SalarySendResult(String status, String submitTime) {
|
||||||
|
this.status = status;
|
||||||
|
this.submitTime = submitTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.domain;
|
||||||
|
|
||||||
|
public class SalaryBatch {
|
||||||
|
public enum Status {
|
||||||
|
DRAFT, BLOCKCHAIN_FETCHED, CONCATENATED, DIGESTED, SIGNED, OUTPUT, SENT
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long id;
|
||||||
|
private String userId;
|
||||||
|
private long schoolId;
|
||||||
|
private long classId;
|
||||||
|
|
||||||
|
// 调取区块信息
|
||||||
|
private String batchId;
|
||||||
|
private String corpWalletId;
|
||||||
|
private String operatorName;
|
||||||
|
private String operatorTimestamp;
|
||||||
|
|
||||||
|
// 拼接原文
|
||||||
|
private String concatenatedMessage;
|
||||||
|
|
||||||
|
// SM3摘要
|
||||||
|
private String digestAlgorithm;
|
||||||
|
private String digestValue;
|
||||||
|
|
||||||
|
// SM2签名
|
||||||
|
private String signature;
|
||||||
|
|
||||||
|
// 输出JSON
|
||||||
|
private String outputJson;
|
||||||
|
|
||||||
|
// 状态
|
||||||
|
private Status status;
|
||||||
|
private String submitTime;
|
||||||
|
|
||||||
|
public static SalaryBatch create(String userId, long schoolId, long classId) {
|
||||||
|
SalaryBatch batch = new SalaryBatch();
|
||||||
|
batch.userId = userId;
|
||||||
|
batch.schoolId = schoolId;
|
||||||
|
batch.classId = classId;
|
||||||
|
batch.status = Status.DRAFT;
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fetchBlockchain(String batchId, String corpWalletId, String operatorName, String timestamp) {
|
||||||
|
this.batchId = batchId;
|
||||||
|
this.corpWalletId = corpWalletId;
|
||||||
|
this.operatorName = operatorName;
|
||||||
|
this.operatorTimestamp = timestamp;
|
||||||
|
this.status = Status.BLOCKCHAIN_FETCHED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void concatenate(String message) {
|
||||||
|
this.concatenatedMessage = message;
|
||||||
|
this.status = Status.CONCATENATED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void computeDigest(String algorithm, String digest) {
|
||||||
|
this.digestAlgorithm = algorithm;
|
||||||
|
this.digestValue = digest;
|
||||||
|
this.status = Status.DIGESTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sign(String signature) {
|
||||||
|
this.signature = signature;
|
||||||
|
this.status = Status.SIGNED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void output(String outputJson) {
|
||||||
|
this.outputJson = outputJson;
|
||||||
|
this.status = Status.OUTPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(String submitTime) {
|
||||||
|
this.submitTime = submitTime;
|
||||||
|
this.status = Status.SENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters and Setters
|
||||||
|
public Long getId() { return id; }
|
||||||
|
public void setId(Long id) { this.id = id; }
|
||||||
|
public String getUserId() { return userId; }
|
||||||
|
public void setUserId(String userId) { this.userId = userId; }
|
||||||
|
public long getSchoolId() { return schoolId; }
|
||||||
|
public void setSchoolId(long schoolId) { this.schoolId = schoolId; }
|
||||||
|
public long getClassId() { return classId; }
|
||||||
|
public void setClassId(long classId) { this.classId = classId; }
|
||||||
|
public String getBatchId() { return batchId; }
|
||||||
|
public void setBatchId(String batchId) { this.batchId = batchId; }
|
||||||
|
public String getCorpWalletId() { return corpWalletId; }
|
||||||
|
public void setCorpWalletId(String corpWalletId) { this.corpWalletId = corpWalletId; }
|
||||||
|
public String getOperatorName() { return operatorName; }
|
||||||
|
public void setOperatorName(String operatorName) { this.operatorName = operatorName; }
|
||||||
|
public String getOperatorTimestamp() { return operatorTimestamp; }
|
||||||
|
public void setOperatorTimestamp(String operatorTimestamp) { this.operatorTimestamp = operatorTimestamp; }
|
||||||
|
public String getConcatenatedMessage() { return concatenatedMessage; }
|
||||||
|
public void setConcatenatedMessage(String concatenatedMessage) { this.concatenatedMessage = concatenatedMessage; }
|
||||||
|
public String getDigestAlgorithm() { return digestAlgorithm; }
|
||||||
|
public void setDigestAlgorithm(String digestAlgorithm) { this.digestAlgorithm = digestAlgorithm; }
|
||||||
|
public String getDigestValue() { return digestValue; }
|
||||||
|
public void setDigestValue(String digestValue) { this.digestValue = digestValue; }
|
||||||
|
public String getSignature() { return signature; }
|
||||||
|
public void setSignature(String signature) { this.signature = signature; }
|
||||||
|
public String getOutputJson() { return outputJson; }
|
||||||
|
public void setOutputJson(String outputJson) { this.outputJson = outputJson; }
|
||||||
|
public Status getStatus() { return status; }
|
||||||
|
public void setStatus(Status status) { this.status = status; }
|
||||||
|
public String getSubmitTime() { return submitTime; }
|
||||||
|
public void setSubmitTime(String submitTime) { this.submitTime = submitTime; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.domain;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface SalaryBatchRepository {
|
||||||
|
SalaryBatch save(SalaryBatch batch);
|
||||||
|
Optional<SalaryBatch> findLatest(String userId, long schoolId, long classId);
|
||||||
|
void update(SalaryBatch batch);
|
||||||
|
}
|
||||||
@ -0,0 +1,81 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.yau.digitalrmb.corporatewallet.domain.SalaryBatch;
|
||||||
|
import com.yau.digitalrmb.corporatewallet.domain.SalaryBatchRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
public class MybatisSalaryBatchRepository implements SalaryBatchRepository {
|
||||||
|
@Resource
|
||||||
|
private SalaryBatchMapper mapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SalaryBatch save(SalaryBatch batch) {
|
||||||
|
SalaryBatchEntity entity = toEntity(batch);
|
||||||
|
mapper.insert(entity);
|
||||||
|
batch.setId(entity.getId());
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<SalaryBatch> findLatest(String userId, long schoolId, long classId) {
|
||||||
|
SalaryBatchEntity entity = mapper.selectOne(
|
||||||
|
new LambdaQueryWrapper<SalaryBatchEntity>()
|
||||||
|
.eq(SalaryBatchEntity::getUserId, userId)
|
||||||
|
.eq(SalaryBatchEntity::getSchoolId, schoolId)
|
||||||
|
.eq(SalaryBatchEntity::getClassId, classId)
|
||||||
|
.eq(SalaryBatchEntity::getDeleted, false)
|
||||||
|
.orderByDesc(SalaryBatchEntity::getCreatedAt)
|
||||||
|
.last("LIMIT 1"));
|
||||||
|
return entity == null ? Optional.empty() : Optional.of(toDomain(entity));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(SalaryBatch batch) {
|
||||||
|
mapper.updateById(toEntity(batch));
|
||||||
|
}
|
||||||
|
|
||||||
|
private SalaryBatchEntity toEntity(SalaryBatch batch) {
|
||||||
|
SalaryBatchEntity entity = new SalaryBatchEntity();
|
||||||
|
entity.setId(batch.getId());
|
||||||
|
entity.setUserId(batch.getUserId());
|
||||||
|
entity.setSchoolId(batch.getSchoolId());
|
||||||
|
entity.setClassId(batch.getClassId());
|
||||||
|
entity.setBatchId(batch.getBatchId());
|
||||||
|
entity.setCorpWalletId(batch.getCorpWalletId());
|
||||||
|
entity.setOperatorName(batch.getOperatorName());
|
||||||
|
entity.setOperatorTimestamp(batch.getOperatorTimestamp());
|
||||||
|
entity.setConcatenatedMessage(batch.getConcatenatedMessage());
|
||||||
|
entity.setDigestAlgorithm(batch.getDigestAlgorithm());
|
||||||
|
entity.setDigestValue(batch.getDigestValue());
|
||||||
|
entity.setSignature(batch.getSignature());
|
||||||
|
entity.setOutputJson(batch.getOutputJson());
|
||||||
|
entity.setStatus(batch.getStatus() == null ? null : batch.getStatus().name());
|
||||||
|
entity.setSubmitTime(batch.getSubmitTime());
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SalaryBatch toDomain(SalaryBatchEntity entity) {
|
||||||
|
SalaryBatch batch = new SalaryBatch();
|
||||||
|
batch.setId(entity.getId());
|
||||||
|
batch.setUserId(entity.getUserId());
|
||||||
|
batch.setSchoolId(entity.getSchoolId());
|
||||||
|
batch.setClassId(entity.getClassId());
|
||||||
|
batch.setBatchId(entity.getBatchId());
|
||||||
|
batch.setCorpWalletId(entity.getCorpWalletId());
|
||||||
|
batch.setOperatorName(entity.getOperatorName());
|
||||||
|
batch.setOperatorTimestamp(entity.getOperatorTimestamp());
|
||||||
|
batch.setConcatenatedMessage(entity.getConcatenatedMessage());
|
||||||
|
batch.setDigestAlgorithm(entity.getDigestAlgorithm());
|
||||||
|
batch.setDigestValue(entity.getDigestValue());
|
||||||
|
batch.setSignature(entity.getSignature());
|
||||||
|
batch.setOutputJson(entity.getOutputJson());
|
||||||
|
batch.setStatus(entity.getStatus() == null ? null : SalaryBatch.Status.valueOf(entity.getStatus()));
|
||||||
|
batch.setSubmitTime(entity.getSubmitTime());
|
||||||
|
return batch;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.yau.digitalrmb.shared.infrastructure.persistence.AuditableEntity;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@TableName("salary_batch")
|
||||||
|
public class SalaryBatchEntity extends AuditableEntity {
|
||||||
|
@TableField("user_id")
|
||||||
|
private String userId;
|
||||||
|
@TableField("school_id")
|
||||||
|
private Long schoolId;
|
||||||
|
@TableField("class_id")
|
||||||
|
private Long classId;
|
||||||
|
@TableField("batch_id")
|
||||||
|
private String batchId;
|
||||||
|
@TableField("corp_wallet_id")
|
||||||
|
private String corpWalletId;
|
||||||
|
@TableField("operator_name")
|
||||||
|
private String operatorName;
|
||||||
|
@TableField("operator_timestamp")
|
||||||
|
private String operatorTimestamp;
|
||||||
|
@TableField("concatenated_message")
|
||||||
|
private String concatenatedMessage;
|
||||||
|
@TableField("digest_algorithm")
|
||||||
|
private String digestAlgorithm;
|
||||||
|
@TableField("digest_value")
|
||||||
|
private String digestValue;
|
||||||
|
@TableField("signature")
|
||||||
|
private String signature;
|
||||||
|
@TableField("output_json")
|
||||||
|
private String outputJson;
|
||||||
|
@TableField("status")
|
||||||
|
private String status;
|
||||||
|
@TableField("submit_time")
|
||||||
|
private String submitTime;
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.infrastructure;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
@Mapper
|
||||||
|
public interface SalaryBatchMapper extends BaseMapper<SalaryBatchEntity> {
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
package com.yau.digitalrmb.corporatewallet.interfaces.rest.dto;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Schema(description = "SM2签名请求")
|
||||||
|
public class SalarySignRequest {
|
||||||
|
@NotBlank(message = "数币操作员私钥不能为空")
|
||||||
|
@Schema(description = "数币操作员私钥(十六进制)", required = true)
|
||||||
|
private String privateKey;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue