package com.vincent.rsf.server.manager.service.impl;
|
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.vincent.rsf.framework.exception.CoolException;
|
import com.vincent.rsf.server.manager.entity.MatnrPrintTemplate;
|
import com.vincent.rsf.server.manager.mapper.MatnrPrintTemplateMapper;
|
import com.vincent.rsf.server.manager.service.MatnrPrintTemplateService;
|
import com.vincent.rsf.server.system.entity.User;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.Date;
|
import java.util.LinkedHashSet;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Set;
|
|
@Service("matnrPrintTemplateService")
|
public class MatnrPrintTemplateServiceImpl
|
extends ServiceImpl<MatnrPrintTemplateMapper, MatnrPrintTemplate>
|
implements MatnrPrintTemplateService {
|
|
private static final Set<String> SUPPORTED_ELEMENT_TYPES = Collections.unmodifiableSet(
|
new LinkedHashSet<>(Arrays.asList("text", "barcode", "qrcode", "line", "rect", "table"))
|
);
|
|
@Override
|
public List<MatnrPrintTemplate> listCurrentTenantTemplates() {
|
List<MatnrPrintTemplate> templates = this.list(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.orderByDesc(MatnrPrintTemplate::getIsDefault)
|
.orderByDesc(MatnrPrintTemplate::getUpdateTime)
|
.orderByDesc(MatnrPrintTemplate::getCreateTime)
|
);
|
return templates == null ? new ArrayList<>() : templates;
|
}
|
|
@Override
|
public MatnrPrintTemplate getCurrentTenantTemplate(Long id) {
|
if (id == null) {
|
throw new CoolException("模板ID不能为空");
|
}
|
MatnrPrintTemplate template = this.getById(id);
|
if (template == null) {
|
throw new CoolException("模板不存在或已被删除");
|
}
|
return template;
|
}
|
|
@Override
|
public MatnrPrintTemplate getCurrentTenantDefaultTemplate() {
|
MatnrPrintTemplate template = this.getOne(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getStatus, 1)
|
.eq(MatnrPrintTemplate::getIsDefault, 1)
|
.orderByDesc(MatnrPrintTemplate::getUpdateTime)
|
.last("limit 1")
|
);
|
if (template != null) {
|
return template;
|
}
|
return this.getOne(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getStatus, 1)
|
.orderByDesc(MatnrPrintTemplate::getUpdateTime)
|
.orderByDesc(MatnrPrintTemplate::getCreateTime)
|
.last("limit 1")
|
);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public MatnrPrintTemplate saveTemplate(MatnrPrintTemplate template) {
|
MatnrPrintTemplate normalized = prepareTemplateForSave(template, false);
|
long currentCount = this.count();
|
boolean shouldDefault = Objects.equals(normalized.getIsDefault(), 1) || currentCount == 0;
|
normalized.setIsDefault(shouldDefault ? 1 : 0);
|
if (shouldDefault) {
|
clearCurrentTenantDefaults();
|
}
|
if (!this.save(normalized)) {
|
throw new CoolException("模板保存失败");
|
}
|
return this.getCurrentTenantTemplate(normalized.getId());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public MatnrPrintTemplate updateTemplate(MatnrPrintTemplate template) {
|
if (template == null || template.getId() == null) {
|
throw new CoolException("模板ID不能为空");
|
}
|
MatnrPrintTemplate existing = getCurrentTenantTemplate(template.getId());
|
MatnrPrintTemplate normalized = prepareTemplateForSave(template, true);
|
normalized.setTenantId(existing.getTenantId());
|
normalized.setCreateBy(existing.getCreateBy());
|
normalized.setCreateTime(existing.getCreateTime());
|
normalized.setDeleted(existing.getDeleted());
|
boolean shouldDefault = Objects.equals(normalized.getIsDefault(), 1);
|
if (shouldDefault) {
|
clearCurrentTenantDefaults();
|
} else if (Objects.equals(existing.getIsDefault(), 1)) {
|
normalized.setIsDefault(1);
|
}
|
if (!this.updateById(normalized)) {
|
throw new CoolException("模板更新失败");
|
}
|
ensureOneDefaultTemplate();
|
return this.getCurrentTenantTemplate(normalized.getId());
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public boolean removeTemplates(List<Long> ids) {
|
if (ids == null || ids.isEmpty()) {
|
throw new CoolException("请选择要删除的模板");
|
}
|
List<MatnrPrintTemplate> templates = this.listByIds(ids);
|
if (templates == null || templates.isEmpty()) {
|
return true;
|
}
|
boolean removedDefault = templates.stream().anyMatch(item -> Objects.equals(item.getIsDefault(), 1));
|
if (!this.removeByIds(ids)) {
|
throw new CoolException("模板删除失败");
|
}
|
if (removedDefault) {
|
ensureOneDefaultTemplate();
|
}
|
return true;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public boolean setDefaultTemplate(Long id) {
|
MatnrPrintTemplate template = getCurrentTenantTemplate(id);
|
clearCurrentTenantDefaults();
|
boolean updated = this.update(new LambdaUpdateWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getId, template.getId())
|
.set(MatnrPrintTemplate::getIsDefault, 1)
|
.set(MatnrPrintTemplate::getUpdateBy, resolveCurrentUserId())
|
.set(MatnrPrintTemplate::getUpdateTime, new Date())
|
);
|
if (!updated) {
|
throw new CoolException("默认模板设置失败");
|
}
|
return true;
|
}
|
|
private MatnrPrintTemplate prepareTemplateForSave(MatnrPrintTemplate template, boolean updating) {
|
if (template == null) {
|
throw new CoolException("模板参数不能为空");
|
}
|
Long currentTenantId = resolveCurrentTenantId();
|
Long currentUserId = resolveCurrentUserId();
|
if (currentTenantId == null) {
|
throw new CoolException("当前租户信息缺失");
|
}
|
String name = normalizeText(template.getName());
|
String code = normalizeText(template.getCode());
|
if (name.isEmpty()) {
|
throw new CoolException("模板名称不能为空");
|
}
|
if (code.isEmpty()) {
|
throw new CoolException("模板编码不能为空");
|
}
|
Map<String, Object> canvasJson = template.getCanvasJson();
|
if (canvasJson == null || canvasJson.isEmpty()) {
|
throw new CoolException("模板画布不能为空");
|
}
|
validateCanvasJson(canvasJson);
|
ensureTemplateCodeUnique(code, updating ? template.getId() : null);
|
|
Date now = new Date();
|
template.setTenantId(currentTenantId)
|
.setName(name)
|
.setCode(code)
|
.setStatus(template.getStatus() == null ? 1 : template.getStatus())
|
.setIsDefault(Objects.equals(template.getIsDefault(), 1) ? 1 : 0)
|
.setMemo(normalizeText(template.getMemo()))
|
.setUpdateBy(currentUserId)
|
.setUpdateTime(now);
|
if (!updating) {
|
template.setCreateBy(currentUserId);
|
template.setCreateTime(now);
|
}
|
return template;
|
}
|
|
private void ensureTemplateCodeUnique(String code, Long excludeId) {
|
long duplicateCount = this.count(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getCode, code)
|
.ne(excludeId != null, MatnrPrintTemplate::getId, excludeId)
|
);
|
if (duplicateCount > 0) {
|
throw new CoolException("模板编码已存在,请更换后重试");
|
}
|
}
|
|
private void clearCurrentTenantDefaults() {
|
this.update(new LambdaUpdateWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getIsDefault, 1)
|
.set(MatnrPrintTemplate::getIsDefault, 0)
|
.set(MatnrPrintTemplate::getUpdateBy, resolveCurrentUserId())
|
.set(MatnrPrintTemplate::getUpdateTime, new Date())
|
);
|
}
|
|
private void ensureOneDefaultTemplate() {
|
long defaultCount = this.count(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getIsDefault, 1)
|
);
|
if (defaultCount > 0) {
|
return;
|
}
|
MatnrPrintTemplate newest = this.getOne(new LambdaQueryWrapper<MatnrPrintTemplate>()
|
.orderByDesc(MatnrPrintTemplate::getUpdateTime)
|
.orderByDesc(MatnrPrintTemplate::getCreateTime)
|
.last("limit 1")
|
);
|
if (newest == null) {
|
return;
|
}
|
this.update(new LambdaUpdateWrapper<MatnrPrintTemplate>()
|
.eq(MatnrPrintTemplate::getId, newest.getId())
|
.set(MatnrPrintTemplate::getIsDefault, 1)
|
.set(MatnrPrintTemplate::getUpdateBy, resolveCurrentUserId())
|
.set(MatnrPrintTemplate::getUpdateTime, new Date())
|
);
|
}
|
|
private void validateCanvasJson(Map<String, Object> canvasJson) {
|
JSONObject root = JSONObject.parseObject(JSON.toJSONString(canvasJson));
|
if (root == null) {
|
throw new CoolException("模板画布格式不正确");
|
}
|
if (root.getInteger("version") == null) {
|
throw new CoolException("模板版本不能为空");
|
}
|
JSONObject canvas = root.getJSONObject("canvas");
|
if (canvas == null) {
|
throw new CoolException("模板画布配置不能为空");
|
}
|
double width = getPositiveNumber(canvas, "width", "画布宽度");
|
double height = getPositiveNumber(canvas, "height", "画布高度");
|
if (width <= 0 || height <= 0) {
|
throw new CoolException("画布尺寸必须大于0");
|
}
|
String unit = normalizeText(canvas.getString("unit"));
|
if (!"mm".equals(unit)) {
|
throw new CoolException("画布单位仅支持 mm");
|
}
|
JSONArray elements = root.getJSONArray("elements");
|
if (elements == null) {
|
throw new CoolException("模板元素不能为空");
|
}
|
for (int index = 0; index < elements.size(); index++) {
|
JSONObject element = elements.getJSONObject(index);
|
if (element == null) {
|
throw new CoolException("模板元素格式不正确");
|
}
|
validateElement(element, index);
|
}
|
}
|
|
private void validateElement(JSONObject element, int index) {
|
String type = normalizeText(element.getString("type"));
|
if (!SUPPORTED_ELEMENT_TYPES.contains(type)) {
|
throw new CoolException("第" + (index + 1) + "个元素类型不支持");
|
}
|
if (normalizeText(element.getString("id")).isEmpty()) {
|
throw new CoolException("第" + (index + 1) + "个元素缺少 ID");
|
}
|
ensureNumber(element, "x", "元素 X 坐标");
|
ensureNumber(element, "y", "元素 Y 坐标");
|
if (!"line".equals(type)) {
|
getPositiveNumber(element, "w", "元素宽度");
|
getPositiveNumber(element, "h", "元素高度");
|
} else {
|
String direction = normalizeText(element.getString("direction"));
|
if (!Arrays.asList("horizontal", "vertical").contains(direction)) {
|
throw new CoolException("线条元素方向仅支持 horizontal 或 vertical");
|
}
|
getPositiveNumber(element, "w", "线条长度");
|
getPositiveNumber(element, "h", "线条粗细");
|
}
|
|
switch (type) {
|
case "text":
|
String contentMode = normalizeText(element.getString("contentMode"));
|
if (!Arrays.asList("static", "template").contains(contentMode)) {
|
throw new CoolException("文本元素内容模式不支持");
|
}
|
if (normalizeText(element.getString("contentTemplate")).isEmpty()) {
|
throw new CoolException("文本元素内容不能为空");
|
}
|
break;
|
case "barcode":
|
if (normalizeText(element.getString("valueTemplate")).isEmpty()) {
|
throw new CoolException("条码元素值模板不能为空");
|
}
|
String symbology = normalizeText(element.getString("symbology"));
|
if (!symbology.isEmpty() && !"CODE128".equals(symbology)) {
|
throw new CoolException("一维码仅支持 CODE128");
|
}
|
break;
|
case "qrcode":
|
if (normalizeText(element.getString("valueTemplate")).isEmpty()) {
|
throw new CoolException("二维码元素值模板不能为空");
|
}
|
break;
|
case "table":
|
if (element.getJSONArray("columns") == null) {
|
throw new CoolException("表格元素 columns 不能为空");
|
}
|
if (element.getJSONArray("rows") == null) {
|
throw new CoolException("表格元素 rows 不能为空");
|
}
|
if (element.getJSONArray("cells") == null) {
|
throw new CoolException("表格元素 cells 不能为空");
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
|
private void ensureNumber(JSONObject object, String key, String label) {
|
if (object.getBigDecimal(key) == null) {
|
throw new CoolException(label + "不能为空");
|
}
|
}
|
|
private double getPositiveNumber(JSONObject object, String key, String label) {
|
if (object.getBigDecimal(key) == null) {
|
throw new CoolException(label + "不能为空");
|
}
|
double value = object.getBigDecimal(key).doubleValue();
|
if (value <= 0) {
|
throw new CoolException(label + "必须大于0");
|
}
|
return value;
|
}
|
|
private String normalizeText(String value) {
|
return value == null ? "" : value.trim();
|
}
|
|
private Long resolveCurrentTenantId() {
|
User loginUser = getCurrentUser();
|
return loginUser == null ? null : loginUser.getTenantId();
|
}
|
|
private Long resolveCurrentUserId() {
|
User loginUser = getCurrentUser();
|
return loginUser == null ? null : loginUser.getId();
|
}
|
|
private User getCurrentUser() {
|
try {
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
if (authentication != null && authentication.getPrincipal() instanceof User) {
|
return (User) authentication.getPrincipal();
|
}
|
} catch (Exception ignored) {
|
}
|
return null;
|
}
|
}
|