package jnpf.dmsService;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import jnpf.base.UserInfo;
|
import jnpf.base.DictionaryDataApi;
|
import jnpf.base.entity.DictionaryDataEntity;
|
import jnpf.dmsEntity.permission.entity.DmsDocumentEntity;
|
import jnpf.dmsEntity.permission.entity.DmsFileVersionEntity;
|
import jnpf.dmsEntity.preview.enums.DmsWatermarkTargetType;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkPositionSnapshot;
|
import jnpf.dmsEntity.preview.model.DmsWatermarkSnapshot;
|
import jnpf.dmsEntity.watermark.DmsWatermarkConfigEntity;
|
import jnpf.dmsEntity.watermark.DmsWatermarkPositionEntity;
|
import jnpf.dmsEntity.watermark.DmsWatermarkParameters;
|
import jnpf.dmsIntegration.audit.DmsVersionStateAuditRow;
|
import jnpf.dmsMapper.DmsDocumentMapper;
|
import jnpf.dmsMapper.DmsVersionStateMapper;
|
import jnpf.dmsMapper.DmsWatermarkConfigMapper;
|
import jnpf.dmsMapper.DmsWatermarkPositionMapper;
|
import jnpf.permission.OrganizeApi;
|
import jnpf.permission.entity.OrganizeEntity;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.beans.BeanUtils;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.util.StringUtils;
|
|
import java.text.SimpleDateFormat;
|
import java.util.ArrayList;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.UUID;
|
import java.util.stream.Collectors;
|
|
@Service
|
@RequiredArgsConstructor
|
public class DmsWatermarkPreviewResolver {
|
private final DmsWatermarkConfigMapper configMapper;
|
private final DmsWatermarkPositionMapper positionMapper;
|
private final DmsDocumentMapper documentMapper;
|
private final DmsVersionStateMapper versionStateMapper;
|
private final OrganizeApi organizeApi;
|
private final DictionaryDataApi dictionaryDataApi;
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolve(UserInfo user, String tenantId,
|
DmsFileVersionEntity version) {
|
return resolve(user, tenantId, version, Scene.PREVIEW, new DmsWatermarkParameters());
|
}
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolveDownload(UserInfo user, String tenantId,
|
DmsFileVersionEntity version) {
|
return resolve(user, tenantId, version, Scene.DOWNLOAD, new DmsWatermarkParameters());
|
}
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolvePrint(UserInfo user, String tenantId,
|
DmsFileVersionEntity version) {
|
return resolve(user, tenantId, version, Scene.PRINT, new DmsWatermarkParameters());
|
}
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolve(UserInfo user, String tenantId,
|
DmsFileVersionEntity version, DmsWatermarkParameters parameters) {
|
return resolve(user, tenantId, version, Scene.PREVIEW, parameters);
|
}
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolveDownload(UserInfo user, String tenantId,
|
DmsFileVersionEntity version, DmsWatermarkParameters parameters) {
|
return resolve(user, tenantId, version, Scene.DOWNLOAD, parameters);
|
}
|
|
@Transactional(readOnly = true)
|
public List<DmsWatermarkSnapshot> resolvePrint(UserInfo user, String tenantId,
|
DmsFileVersionEntity version, DmsWatermarkParameters parameters) {
|
return resolve(user, tenantId, version, Scene.PRINT, parameters);
|
}
|
|
private List<DmsWatermarkSnapshot> resolve(UserInfo user, String tenantId,
|
DmsFileVersionEntity version,
|
Scene scene, DmsWatermarkParameters parameters) {
|
DmsWatermarkParameters options = parameters.normalized();
|
List<String> businessTypes = options.getWatermarkBusinessTypes();
|
if (businessTypes == null || businessTypes.isEmpty()) return Collections.emptyList();
|
List<DictionaryDataEntity> dictionary = dictionaryDataApi.getList("879384732964547653", "true");
|
if (dictionary == null) throw new jnpf.exception.DataException("水印业务类型字典查询失败");
|
java.util.Set<String> allowedTypes = dictionary.stream()
|
.filter(item -> item != null && item.getDeleteMark() == null
|
&& Integer.valueOf(1).equals(item.getEnabledMark())
|
&& "879384732964547653".equals(item.getDictionaryTypeId()))
|
.map(DictionaryDataEntity::getEnCode)
|
.collect(Collectors.toSet());
|
if (!allowedTypes.containsAll(businessTypes)) {
|
throw new jnpf.exception.DataException("水印业务类型包含无效的字典编码");
|
}
|
if (DmsWatermarkTargetType.from(version.getFileName(), version.getMimeType())
|
== DmsWatermarkTargetType.UNSUPPORTED) {
|
return Collections.emptyList();
|
}
|
DmsVersionStateAuditRow state = versionStateMapper.selectAuditState(tenantId, version.getId());
|
if (state == null || state.getLifecycleStatus() == null
|
|| !java.util.Set.of("EFFECTIVE", "SUPERSEDED", "EXPIRED",
|
"REVOKED", "OBSOLETE", "INVALIDATED").contains(state.getLifecycleStatus())) {
|
return Collections.emptyList();
|
}
|
boolean current = "EFFECTIVE".equals(state.getLifecycleStatus());
|
|
LambdaQueryWrapper<DmsWatermarkConfigEntity> configQuery =
|
new LambdaQueryWrapper<DmsWatermarkConfigEntity>()
|
.eq(DmsWatermarkConfigEntity::getTenantId, tenantId)
|
.eq(DmsWatermarkConfigEntity::getEnabled, true);
|
if (scene == Scene.DOWNLOAD) {
|
configQuery.eq(DmsWatermarkConfigEntity::getLoadDownload, true);
|
} else if (scene == Scene.PRINT) {
|
configQuery.eq(DmsWatermarkConfigEntity::getLoadPrint, true);
|
} else {
|
configQuery.eq(DmsWatermarkConfigEntity::getLoadPreview, true);
|
}
|
if (current) {
|
configQuery.in(DmsWatermarkConfigEntity::getVersionScope, "ALL", "CURRENT");
|
} else {
|
configQuery.eq(DmsWatermarkConfigEntity::getVersionScope, "ALL");
|
}
|
List<DmsWatermarkConfigEntity> configs = configMapper.selectList(configQuery
|
.isNull(DmsWatermarkConfigEntity::getDeletedAt)
|
.orderByAsc(DmsWatermarkConfigEntity::getCreatedAt));
|
if (configs.isEmpty()) {
|
return Collections.emptyList();
|
}
|
|
DmsDocumentEntity document = documentMapper.selectByTenantAndId(tenantId,
|
version.getDocumentId());
|
VariableContext variables = variables(user, document, version, current);
|
List<UUID> configIds = configs.stream().map(DmsWatermarkConfigEntity::getId)
|
.collect(Collectors.toList());
|
java.util.Set<UUID> matchingIds = new java.util.HashSet<>(configMapper.selectMatchingConfigIds(
|
tenantId, configIds, businessTypes));
|
if (matchingIds.isEmpty()) return Collections.emptyList();
|
List<DmsWatermarkPositionEntity> positions = positionMapper.selectList(
|
new LambdaQueryWrapper<DmsWatermarkPositionEntity>()
|
.eq(DmsWatermarkPositionEntity::getTenantId, tenantId)
|
.in(DmsWatermarkPositionEntity::getConfigId, configIds)
|
.orderByAsc(DmsWatermarkPositionEntity::getSortOrder));
|
|
List<DmsWatermarkSnapshot> result = new ArrayList<>();
|
for (DmsWatermarkConfigEntity config : configs) {
|
if (!matchingIds.contains(config.getId())) continue;
|
boolean custom = "BARCODE".equals(config.getWatermarkType())
|
&& DmsWatermarkParameters.CUSTOM_BARCODE_TEMPLATE.equals(config.getContentTemplate());
|
if (custom && options.getCustomBarcode() == null) continue;
|
List<DmsWatermarkPositionSnapshot> configuredPositions = positions.stream()
|
.filter(position -> config.getId().equals(position.getConfigId()))
|
.map(this::positionSnapshot)
|
.collect(Collectors.toList());
|
List<DmsWatermarkParameters.CustomBarcode> entries = custom
|
? options.getCustomBarcode() : Collections.singletonList(null);
|
for (DmsWatermarkParameters.CustomBarcode entry : entries) {
|
DmsWatermarkSnapshot snapshot = new DmsWatermarkSnapshot();
|
BeanUtils.copyProperties(config, snapshot);
|
snapshot.setHorizontalAlign(config.getHorizontalAlign() == null ? "LEFT" : config.getHorizontalAlign());
|
snapshot.setVerticalAlign(config.getVerticalAlign() == null ? "TOP" : config.getVerticalAlign());
|
snapshot.setCustomBarcode(custom);
|
// Barcode values and labels are literal runtime data, never template expressions.
|
snapshot.setContent(custom ? entry.getBarValue()
|
: replaceVariables(config.getContentTemplate(), variables));
|
if (custom) {
|
snapshot.setBarcodeText(entry.getBarText());
|
snapshot.setShowBarcodeText(true);
|
snapshot.setRenderPages(entry.getPage() == null ? null
|
: new ArrayList<>(Collections.singletonList(entry.getPage())));
|
}
|
if ("BARCODE".equals(snapshot.getWatermarkType())
|
&& "CODE_128".equals(snapshot.getBarcodeFormat())
|
&& snapshot.getContent() != null
|
&& snapshot.getContent().chars().anyMatch(c -> c > 127 && (c < 241 || c > 244))) {
|
throw new jnpf.exception.DataException("水印“" + config.getName()
|
+ "”使用 Code 128,但条码内容包含中文等不支持的字符,请将条码格式改为二维码");
|
}
|
snapshot.setPositions(configuredPositions);
|
if (!snapshot.getPositions().isEmpty()) result.add(snapshot);
|
}
|
}
|
return result;
|
}
|
|
private VariableContext variables(UserInfo user, DmsDocumentEntity document,
|
DmsFileVersionEntity version, boolean current) {
|
String department = user.getOrganize();
|
if (!StringUtils.hasText(department) && StringUtils.hasText(user.getOrganizeId())) {
|
OrganizeEntity organization = organizeApi.getInfoById(user.getOrganizeId().trim());
|
department = organization == null ? null : organization.getFullName();
|
}
|
String userName = StringUtils.hasText(user.getUserName())
|
? user.getUserName().trim() : user.getUserId().trim();
|
String versionText = StringUtils.hasText(version.getVersionLabel())
|
? version.getVersionLabel().trim()
|
: version.getVersionNo() == null ? "" : String.valueOf(version.getVersionNo());
|
return new VariableContext(userName, text(department),
|
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()),
|
version.getFileName(), document == null ? "" : text(document.getDocumentNo()),
|
versionText, current ? "现行版本" : "历史版本");
|
}
|
|
private String replaceVariables(String template, VariableContext value) {
|
if (template == null) {
|
return null;
|
}
|
return template.replace("{/CUN}", value.userName)
|
.replace("{/CDN}", value.department)
|
.replace("{/CDT}", value.time)
|
.replace("{/FILENAME}", value.fileName)
|
.replace("{/FILENO}", value.fileNo)
|
.replace("{/VERSION}", value.version)
|
.replace("{/FILESTATE}", value.fileState);
|
}
|
|
private DmsWatermarkPositionSnapshot positionSnapshot(DmsWatermarkPositionEntity value) {
|
DmsWatermarkPositionSnapshot result = new DmsWatermarkPositionSnapshot();
|
BeanUtils.copyProperties(value, result);
|
return result;
|
}
|
|
private String text(String value) {
|
return value == null ? "" : value.trim();
|
}
|
|
private enum Scene {
|
PREVIEW,
|
DOWNLOAD,
|
PRINT
|
}
|
|
private static final class VariableContext {
|
private final String userName;
|
private final String department;
|
private final String time;
|
private final String fileName;
|
private final String fileNo;
|
private final String version;
|
private final String fileState;
|
|
private VariableContext(String userName, String department, String time, String fileName,
|
String fileNo, String version, String fileState) {
|
this.userName = userName;
|
this.department = department;
|
this.time = time;
|
this.fileName = fileName;
|
this.fileNo = fileNo;
|
this.version = version;
|
this.fileState = fileState;
|
}
|
}
|
}
|