Compare commits

...

10 Commits

Author SHA1 Message Date
86158 1a9dadec7e Merge branch 'plp'
# Conflicts:
#	yudao-module-mes/yudao-module-mes-biz/src/main/java/cn/iocoder/yudao/module/mes/service/criticalcomponent/CriticalComponentServiceImpl.java
3 months ago
HuangHuiKang baadf3c1fe fix:优化修改告警页面分页 3 months ago
HuangHuiKang 62eea2d16a fix:优化历史数据分页 3 months ago
86158 aa7c6da293 Merge branch 'refs/heads/plp'
# Conflicts:
#	yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/mold/MoldServiceImpl.java
3 months ago
HuangHuiKang d2c45b0ff2 fix:修改模具下模问题 3 months ago
kkk-ops 6464295857 Merge branch 'main' of https://git.ngsk.tech/linweidong/besure_server 3 months ago
kkk-ops f4819d840d 新增模具页面 3 months ago
HuangHuiKang 1ad8100be1 fix:修改模具上模为多选,新增下模相关接口 3 months ago
HuangHuiKang 628311098b fix:设备管理模块-新增编码重复问题 3 months ago
HuangHuiKang 50081338d9 fix:tdengine问题 3 months ago

@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandDO;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandProductDO;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairDO;
import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO;
import cn.iocoder.yudao.module.erp.service.mold.MoldBrandService;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import io.swagger.v3.oas.annotations.Operation;
@ -99,6 +100,14 @@ public class MoldBrandController {
ExcelUtils.write(response, "模具型号.xls", "数据", MoldBrandRespVO.class, moldBrandRespVOS);
}
@GetMapping("/tree")
@Operation(summary = "获得设备类型树")
@PreAuthorize("@ss.hasPermission('mes:device-type:query')")
public CommonResult<List<MoldBrandTreeRespVO>> getDeviceTypeTree() {
List<MoldBrandTreeRespVO> tree = moldBrandService.getMoldBrandTree();
return success(tree);
}
// ==================== 子表(模具) ====================
@GetMapping("/getMoldList")
@Operation(summary = "获得模具型号")

@ -96,4 +96,11 @@ public class MoldController {
BeanUtils.toBean(list, MoldRespVO.class));
}
@GetMapping("/getInTransitMoldAllList")
@Operation(summary = "获得上下模模具列表(在途-3")
public CommonResult<List<MoldDO>> getInTransitMoldAllList() {
List<MoldDO> doList = moldService.getInTransitMoldAllList();
return success(doList);
}
}

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.erp.controller.admin.mold.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(description = "管理后台 - 模具类型树形结构 Response VO")
public class MoldBrandTreeRespVO extends MoldBrandRespVO{
@Schema(description = "模具类型列表")
private List<MoldBrandTreeRespVO> children;
@Schema(description = "是否叶子节点", example = "true")
private Boolean leaf = true;
}

@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.common.controller.admin.mold.vo.*;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandDO;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldBrandProductDO;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import javax.validation.Valid;
@ -180,4 +181,6 @@ public interface MoldBrandService {
if(ids.isEmpty())return new HashMap<>();
return convertMap(getMoldBrandList(ids), MoldBrandDO::getId);
}
List<MoldBrandTreeRespVO> getMoldBrandTree();
}

@ -15,6 +15,7 @@ import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldrepair.MoldRepairLineDO;
import cn.iocoder.yudao.module.common.dal.dataobject.moldticketresults.MoldTicketResultsDO;
import cn.iocoder.yudao.module.erp.controller.admin.mold.vo.MoldBrandTreeRespVO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.common.dal.mysql.mold.MoldBrandMapper;
@ -28,7 +29,6 @@ import cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -343,4 +343,35 @@ public class MoldBrandServiceImpl implements MoldBrandService {
private void deleteMoldBrandProductByBrandId(Long brandId) {
moldBrandProductMapper.deleteByBrandId(brandId);
}
@Override
public List<MoldBrandTreeRespVO> getMoldBrandTree() {
// 1. 查询所有模具类型
List<MoldBrandDO> allMoldBrands = moldBrandMapper.selectList();
// 2. 构建树形结构
return buildMoldBrandTree(allMoldBrands);
}
/**
*
*/
private List<MoldBrandTreeRespVO> buildMoldBrandTree(List<MoldBrandDO> allMoldBrands) {
return allMoldBrands.stream()
.map(this::convertToTreeRespVO)
.collect(Collectors.toList());
}
private MoldBrandTreeRespVO convertToTreeRespVO(MoldBrandDO moldBrand) {
// 使用BeanUtils或手动设置属性
MoldBrandTreeRespVO respVO = new MoldBrandTreeRespVO();
// 复制公共属性假设MoldBrandRespVO有对应的方法
BeanUtils.copyProperties(moldBrand, respVO);
// 设置树状结构属性
respVO.setChildren(new ArrayList<>()); // 空子节点
respVO.setLeaf(true); // 叶子节点
return respVO;
}
}

@ -98,4 +98,6 @@ public interface MoldService {
}
List<MoldRespVO> buildMoldVOList(List<MoldDO> list);
List<MoldDO> getInTransitMoldAllList();
}

@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
import cn.iocoder.yudao.module.erp.dal.dataobject.stock.ErpWarehouseDO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@ -123,4 +124,9 @@ public class MoldServiceImpl implements MoldService {
}
return BeanUtils.toBean(list, MoldRespVO.class);
}
@Override
public List<MoldDO> getInTransitMoldAllList() {
return moldMapper.selectList(Wrappers.<MoldDO>lambdaQuery().eq(MoldDO::getStatus,3));
}
}

@ -38,9 +38,15 @@ public interface ErrorCodeConstants {
//======================================数据采集相关=================================================
ErrorCode DEVICE_MODEL_NOT_EXISTS = new ErrorCode(1_003_000_001, "采集设备模型不存在");
ErrorCode DEVICE_MODEL_CODE_EXISTS = new ErrorCode(1_003_000_002, "采集设备模型编码已存在");
ErrorCode DEVICE_CODE_ALREADY_EXISTS = new ErrorCode(1_003_000_002, "采集设备编码已存在");
ErrorCode DEVICE_ID_MODEL_NOT_EXISTS = new ErrorCode(1_003_000_003, "该设备模型ID不能为空");
ErrorCode POINT_ID_MODEL_NOT_EXISTS = new ErrorCode(1_003_000_004, "该点位参数ID不能为空");
ErrorCode DEVICE_MODEL_ATTRIBUTE_NOT_EXISTS = new ErrorCode(1_003_000_005, "采集设备模型点位不存在");
ErrorCode DEVICE_MODEL_POINT_CODE_EXISTS = new ErrorCode(1_003_000_005, "采集设备采集点位编码已存在");
ErrorCode DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS = new ErrorCode(1_003_000_005, "采集设备模型点位编码已存在");
ErrorCode DEVICE_ATTRIBUTE_NOT_EXISTS = new ErrorCode(1_003_000_006, "设备属性不存在");
ErrorCode DEVICE_ATTRIBUTE_TYPE_NOT_EXISTS = new ErrorCode(1_003_000_007, "采集点分类不存在");
ErrorCode DEVICE_CODE_EXISTS = new ErrorCode(1_003_000_000, "采集点编码已存在");

@ -183,11 +183,13 @@ public class DeviceController {
@GetMapping("/historyRecord")
@Operation(summary = "历史记录查询")
// @PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<Map<String, Object>>> historyRecord(@RequestParam("deviceId") Long deviceId,
public CommonResult<PageResult<Map<String, Object>>> historyRecord(@RequestParam("deviceId") Long deviceId,
@RequestParam(name = "collectionStartTime", required = false) String collectionStartTime,
@RequestParam(name = "collectionEndTime", required = false) String collectionEndTime
@RequestParam(name = "collectionEndTime", required = false) String collectionEndTime,
@RequestParam(name = "pageNo", required = false, defaultValue = "1") Integer page,
@RequestParam(name = "pageSize", required = false, defaultValue = "10") Integer pageSize
) throws JsonProcessingException {
List<Map<String, Object>> deviceContactModelDO=deviceService.historyRecord(deviceId,collectionStartTime,collectionEndTime);
PageResult<Map<String, Object>> deviceContactModelDO=deviceService.historyRecord(deviceId,collectionStartTime,collectionEndTime,page,pageSize);
return success(deviceContactModelDO);
}
@ -212,6 +214,16 @@ public class DeviceController {
return success(deviceService.getDeviceAttributePage(pageParam, deviceModelAttributePageReqVO));
}
@GetMapping("/device-attribute/list")
@Operation(summary = "获得设备属性列表")
@Parameter(name = "deviceId", description = "设备id")
@PreAuthorize("@ss.hasPermission('iot:device:query')")
public CommonResult<List<DeviceContactModelDO>> getDeviceAttributeList(@RequestParam(name = "deviceId") Long deviceId) {
return success(deviceService.getDeviceAttributeList(deviceId));
}
@PostMapping("/device-attribute/create")
@Operation(summary = "创建设备属性")
@PreAuthorize("@ss.hasPermission('iot:device:create')")

@ -104,4 +104,13 @@ public class DevicePointRulesController {
BeanUtils.toBean(list, DevicePointRulesRespVO.class));
}
@GetMapping("/getList")
@Operation(summary = "获得点位规则列表")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:device-point-rules:query')")
public CommonResult<List<DevicePointRulesDO>> getList(@RequestParam("id") Long id) {
List<DevicePointRulesDO> devicePointRules = devicePointRulesService.getList(id);
return success(devicePointRules);
}
}

@ -30,7 +30,7 @@ public interface DeviceContactModelMapper extends BaseMapperX<DeviceContactModel
.eq(Objects.nonNull(device.getAttributeType()), DeviceContactModelDO::getAttributeType, device.getAttributeType())
// 必要的条件如deviceModelId保留直接eq条件
.eq(DeviceContactModelDO::getDeviceId, device.getDeviceId())
.orderByAsc(DeviceContactModelDO::getSort));
.orderByDesc(DeviceContactModelDO::getId));
}

@ -49,7 +49,7 @@ public interface DeviceModelAttributeMapper extends BaseMapperX<DeviceModelAttri
.eqIfPresent(DeviceModelAttributeDO::getRemark, reqVO.getRemark())
.eqIfPresent(DeviceModelAttributeDO::getDeviceModelId, reqVO.getId())
.betweenIfPresent(DeviceModelAttributeDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(DeviceModelAttributeDO::getCreateTime);
.orderByDesc(DeviceModelAttributeDO::getId);
if(reqVO.getIds() !=null && StringUtils.isNotBlank(reqVO.getIds())){

@ -123,7 +123,7 @@ public interface DeviceService {
Map<String, List<Map<String, Object>>> singleDevice(Long deviceId) throws JsonProcessingException;
List<Map<String, Object>> historyRecord(Long deviceId,String collectionStartTime, String collectionEndTime);
PageResult<Map<String, Object>> historyRecord(Long deviceId,String collectionStartTime, String collectionEndTime,Integer page,Integer size);
Map<Long, Map<String, Object>> createDeviceDataMap(Long deviceId);
@ -136,4 +136,6 @@ public interface DeviceService {
DeviceOperationStatusRespVO getDeviceOperationalStatus();
List<Map<String, Object>> getMultiDeviceAttributes(String deviceIds);
List<DeviceContactModelDO> getDeviceAttributeList(Long deviceId);
}

@ -108,16 +108,28 @@ public class DeviceServiceImpl implements DeviceService {
@Resource
private DeviceOperationRecordMapper deviceOperationRecordMapper;
@Override
@Transactional(rollbackFor = Exception.class)
public DeviceDO createDevice(DeviceSaveReqVO createReqVO) {
if(StringUtils.isNotBlank(createReqVO.getReadTopic())){
DeviceDO temp = deviceMapper.selectByTopic(createReqVO.getReadTopic());
if (temp!=null){
throw exception(DEVICE_EXISTS);
}
// if(StringUtils.isNotBlank(createReqVO.getReadTopic())){
// DeviceDO temp = deviceMapper.selectByTopic(createReqVO.getReadTopic());
// if (temp!=null){
// throw exception(DEVICE_EXISTS);
// }
// }
//判断编码是否唯一
boolean exists = deviceMapper.exists(
Wrappers.<DeviceDO>lambdaQuery()
.eq(DeviceDO::getDeviceCode, createReqVO.getDeviceCode()));
if (exists) {
throw exception(DEVICE_CODE_ALREADY_EXISTS);
}
DeviceModelDO deviceModelDO = deviceModelMapper.selectById(createReqVO.getDeviceModelId());
// 插入
@ -679,78 +691,107 @@ public class DeviceServiceImpl implements DeviceService {
}
@Override
public List<Map<String, Object>> historyRecord(Long deviceId,String collectionStartTime, String collectionEndTime) {
public PageResult<Map<String, Object>> historyRecord(Long deviceId, String collectionStartTime, String collectionEndTime,Integer page,
Integer pageSize) {
List<Map<String, Object>> resultList = new ArrayList<>();
if (deviceId == null) {
return null;
}
try {
// 1. 获取设备数据列表
List<Map<String, Object>> deviceDataList = tdengineService.getstDeviceDataOrderByTimeDesc(deviceId,collectionStartTime,collectionEndTime,null);
List<Map<String, Object>> deviceDataList = tdengineService.getstDeviceDataOrderByTimeDescPage(
deviceId, collectionStartTime, collectionEndTime, page, pageSize
);
// 2. 获取属性类型映射
long total = tdengineService.queryDeviceDataTotal(deviceId, collectionStartTime, collectionEndTime);
if (deviceDataList.isEmpty()) {
return null;
}
// 2. 获取属性类型映射 (ID -> Name) 并构建缓存,避免重复数据库查询
Map<Long, String> idToNameMap = deviceAttributeTypeMapper.selectList()
.stream()
.collect(Collectors.toMap(
DeviceAttributeTypeDO::getId,
DeviceAttributeTypeDO::getName
));
.collect(Collectors.toMap(DeviceAttributeTypeDO::getId, DeviceAttributeTypeDO::getName));
// 额外缓存数字ID -> 名称防止同一个ID多次查询数据库
Map<Long, String> attributeTypeCache = new HashMap<>();
ObjectMapper objectMapper = new ObjectMapper();
// 3. 遍历每个时间点的数据
// 3. 遍历每条设备数据
for (Map<String, Object> deviceData : deviceDataList) {
String queryDataJson = (String) deviceData.get("queryData");
Timestamp timestamp = (Timestamp) deviceData.get("timestamp");
if (StringUtils.isNotBlank(queryDataJson) && timestamp != null) {
List<Map<String, Object>> dataList = new ObjectMapper().readValue(
queryDataJson,
new TypeReference<List<Map<String, Object>>>() {}
);
// 按属性类型分组
Map<String, List<Map<String, Object>>> groupedData = new LinkedHashMap<>();
if (StringUtils.isBlank(queryDataJson) || timestamp == null) {
continue; // 跳过无效数据
}
for (Map<String, Object> data : dataList) {
String attributeTypeName = "其他";
String typeStr = (String) data.get("attributeType");
if (typeStr != null) {
try {
attributeTypeName = typeStr;
} catch (Exception e) {
attributeTypeName = "未知";
}
}
List<Map<String, Object>> dataList = objectMapper.readValue(
queryDataJson, new TypeReference<List<Map<String, Object>>>() {}
);
Map<String, Object> simplifiedData = new HashMap<>();
simplifiedData.put("addressValue", data.get("addressValue"));
simplifiedData.put("attributeName", data.get("attributeName"));
// 4. 按属性类型分组
Map<String, List<Map<String, Object>>> groupedData = new LinkedHashMap<>();
groupedData
.computeIfAbsent(attributeTypeName, k -> new ArrayList<>())
.add(simplifiedData);
}
for (Map<String, Object> data : dataList) {
String attributeTypeName = "其他";
Object typeObj = data.get("attributeType");
// 创建当前时间点的Map
Map<String, Object> timePointData = new LinkedHashMap<>();
if (typeObj != null) {
String typeStr = typeObj.toString();
// 添加属性分组
for (Map.Entry<String, List<Map<String, Object>>> entry : groupedData.entrySet()) {
timePointData.put(entry.getKey(), entry.getValue());
try {
// 尝试当作数字 ID
Long typeId = Long.parseLong(typeStr);
// 先从缓存查
if (attributeTypeCache.containsKey(typeId)) {
attributeTypeName = attributeTypeCache.get(typeId);
} else {
// 查数据库
String nameFromDb = idToNameMap.get(typeId);
if (nameFromDb != null) {
attributeTypeName = nameFromDb;
} else {
attributeTypeName = typeStr; // 查不到就用原值
}
attributeTypeCache.put(typeId, attributeTypeName);
}
} catch (NumberFormatException e) {
// 不是数字,直接用原字符串
attributeTypeName = typeStr;
}
}
// 添加收集时间
timePointData.put("collectTime", timestamp.toString());
// 构建属性数据 Map
Map<String, Object> simplifiedData = new HashMap<>();
simplifiedData.put("addressValue", data.get("addressValue"));
simplifiedData.put("attributeName", data.get("attributeName"));
resultList.add(timePointData);
groupedData.computeIfAbsent(attributeTypeName, k -> new ArrayList<>())
.add(simplifiedData);
}
// 5. 构建时间点 Map
Map<String, Object> timePointData = new LinkedHashMap<>(groupedData);
timePointData.put("collectTime", timestamp.toString());
resultList.add(timePointData);
}
return new PageResult<>(resultList, total);
} catch (Exception e) {
System.out.println("处理设备数据时发生异常: " + e.getMessage());
log.error("处理设备数据时发生异常", e);
return PageResult.empty();
}
}
return resultList;
}
private void validateDeviceAttributeExists(Long id) {
@ -934,4 +975,11 @@ public class DeviceServiceImpl implements DeviceService {
return result;
}
@Override
public List<DeviceContactModelDO> getDeviceAttributeList(Long deviceId) {
return deviceContactModelMapper.selectList(Wrappers.<DeviceContactModelDO>lambdaQuery()
.eq(DeviceContactModelDO::getDeviceId,deviceId)
.orderByDesc(DeviceContactModelDO::getId));
}
}

@ -80,8 +80,8 @@ public class TDengineService {
public Map<String, Object> getLatestDeviceData(Long id) {
String tableName = "d_" + id;
// 修改SQL对每个列单独使用last_row函数并指定别名
String sql = "SELECT last_row(ts) as ts, last_row(query_data) as query_data FROM besure." + tableName;
String sql = "SELECT ts, query_data FROM besure." + tableName +
" ORDER BY ts DESC LIMIT 1";
try {
return jdbcTemplate.queryForObject(sql, new RowMapper<Map<String, Object>>() {
@ -266,6 +266,96 @@ public class TDengineService {
}
}
/**
*
* @param id ID
* @return
*/
@DS("tdengine")
public List<Map<String, Object>> getstDeviceDataOrderByTimeDescPage(Long id,String StartTime, String EndTime,Integer page,
Integer pageSize) {
String tableName = "d_" + id;
StringBuilder sqlBuilder = new StringBuilder();
List<Object> params = new ArrayList<>();
sqlBuilder.append("SELECT ts, query_data FROM besure.").append(tableName).append(" WHERE 1=1");
if (StartTime != null) {
// 直接将时间字符串拼接到SQL中
sqlBuilder.append(" AND ts >= '").append(StartTime).append("'");
}
if (EndTime != null) {
sqlBuilder.append(" AND ts <= '").append(EndTime).append("'");
}
sqlBuilder.append(" ORDER BY ts DESC");
// 分页处理
if (page != null && pageSize != null && page > 0 && pageSize > 0) {
int offset = (page - 1) * pageSize;
sqlBuilder.append(" LIMIT ").append(offset).append(",").append(pageSize);
}
try {
return jdbcTemplate.query(sqlBuilder.toString(), new RowMapper<Map<String, Object>>() {
@Override
public Map<String, Object> mapRow(ResultSet rs, int rowNum) throws SQLException {
Map<String, Object> result = new HashMap<>();
result.put("timestamp", rs.getTimestamp("ts"));
result.put("deviceId", id);
// 读取 query_data二进制字段
byte[] blob = rs.getBytes("query_data");
result.put("queryData", decodeQueryData(blob));
return result;
}
});
} catch (Exception e) {
// log.error("查询设备" + id + "的最新数据时发生异常", e);
// e.printStackTrace();
return Collections.singletonList(createEmptyResult(id));
}
}
/**
*
*
* @param deviceId ID
* @param startTime
* @param endTime
* @return
*/
@DS("tdengine")
public long queryDeviceDataTotal(Long deviceId, String startTime, String endTime) {
if (deviceId == null) {
return 0L;
}
String tableName = "d_" + deviceId;
StringBuilder countSql = new StringBuilder("SELECT COUNT(*) FROM besure." + tableName + " WHERE 1=1");
if (startTime != null) {
countSql.append(" AND ts >= '").append(startTime).append("'");
}
if (endTime != null) {
countSql.append(" AND ts <= '").append(endTime).append("'");
}
try {
Long total = jdbcTemplate.queryForObject(countSql.toString(), Long.class);
return total != null ? total : 0L;
} catch (Exception e) {
log.error("查询设备 {} 总条数异常", deviceId, e);
return 0L;
}
}
/**
* TDengine
*

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.devicecontactmodel;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicecontactmodel.DeviceContactModelDO;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO;
import cn.iocoder.yudao.module.iot.dal.mysql.deviceattributetype.DeviceAttributeTypeMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
@ -17,6 +18,8 @@ import java.util.List;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.DEVICE_CONTACT_MODEL_NOT_EXISTS;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODEL_POINT_CODE_EXISTS;
/**
* - Service
@ -34,6 +37,18 @@ public class DeviceContactModelServiceImpl implements DeviceContactModelService
@Override
public Long createDeviceContactModel(DeviceContactModelSaveReqVO createReqVO) {
//判断编码是否唯一
boolean exists = deviceContactModelMapper.exists(
Wrappers.<DeviceContactModelDO>lambdaQuery()
.eq(DeviceContactModelDO::getDeviceId, createReqVO.getDeviceId())
.eq(DeviceContactModelDO::getAttributeCode, createReqVO.getAttributeCode()));
if (exists) {
throw exception(DEVICE_MODEL_POINT_CODE_EXISTS);
}
// 插入
DeviceContactModelDO deviceContactModel = BeanUtils.toBean(createReqVO, DeviceContactModelDO.class);
// deviceContactModel.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName());

@ -56,7 +56,18 @@ import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
@Override
public Long createDeviceModelAttribute(DeviceModelAttributeSaveReqVO createReqVO) {
// 插入
//判断编码是否唯一
boolean exists = deviceModelAttributeMapper.exists(
Wrappers.<DeviceModelAttributeDO>lambdaQuery()
.eq(DeviceModelAttributeDO::getDeviceModelId, createReqVO.getDeviceModelId())
.eq(DeviceModelAttributeDO::getAttributeCode, createReqVO.getAttributeCode()));
if (exists) {
throw exception(DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS);
}
// 插入
DeviceModelAttributeDO deviceModelAttribute = BeanUtils.toBean(createReqVO, DeviceModelAttributeDO.class);
// deviceModelAttribute.setTypeName(deviceAttributeTypeMapper.selectById(createReqVO.getAttributeCode()).getName());
deviceModelAttributeMapper.insert(deviceModelAttribute);

@ -52,4 +52,5 @@ public interface DevicePointRulesService {
*/
PageResult<DevicePointRulesDO> getDevicePointRulesPage(DevicePointRulesPageReqVO pageReqVO);
List<DevicePointRulesDO> getList(Long id);
}

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.iot.service.devicepointrules;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -78,4 +79,10 @@ public class DevicePointRulesServiceImpl implements DevicePointRulesService {
return devicePointRulesMapper.selectPage(pageReqVO);
}
@Override
public List<DevicePointRulesDO> getList(Long id) {
return devicePointRulesMapper.selectList(Wrappers.<DevicePointRulesDO>lambdaQuery()
.eq(DevicePointRulesDO::getDeviceId,id).eq(DevicePointRulesDO::getIdentifier,"ALARM").orderByDesc(DevicePointRulesDO::getDeviceId));
}
}

@ -147,6 +147,8 @@ public interface ErrorCodeConstants {
ErrorCode TICKET_RESULTS_NOT_EXISTS = new ErrorCode(1002000013, "工单检验结果不存在");
ErrorCode TICKET_RESULTS_ID_NOT_NULL = new ErrorCode(1002000014, "工单检验结果Id不存在");
ErrorCode CRITICAL_COMPONENT_NOT_EXISTS = new ErrorCode(1002000015, "设备关键件不存在");
ErrorCode CRITICAL_COMPONENT_CODE_EXISTS = new ErrorCode(1002000015, "设备关键件编码已存在");
ErrorCode CRITICAL_COMPONENT_REFERENCES= new ErrorCode(1002000015, "存在设备关键件已被引用,请先删除引用");
ErrorCode REPAIR_TEMS_NOT_EXISTS = new ErrorCode(1002000016, "维修项目不存在");

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
import cn.iocoder.yudao.module.mes.service.deviceledger.DeviceLedgerService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
@ -25,6 +26,7 @@ import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -64,24 +66,41 @@ public class MoldOperateController {
@Operation(summary = "创建模具上下模")
@PreAuthorize("@ss.hasPermission('mes:mold-operate:create')")
public CommonResult<Long> createMoldOperate(@Valid @RequestBody MoldOperateSaveReqVO createReqVO) {
if (Objects.equals(createReqVO.getOperateType(), "1")) {
DeviceLedgerDO deviceLedger = deviceLedgerService.getDeviceLedger(createReqVO.getDeviceId());
MoldDO moldDO = moldService.getMold(createReqVO.getMoldId());
moldDO.setMachineId(createReqVO.getDeviceId());
moldDO.setMachineName(deviceLedger.getDeviceName());
moldDO.setStatus(0); // 在机 0 在库 1
moldService.updateMold(BeanUtils.toBean(moldDO, MoldSaveReqVO.class));
deviceLedger.setMoldId(Long.toString(createReqVO.getMoldId()));
List<Long> idList = Arrays.stream(createReqVO.getMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
for (Long id : idList) {
MoldDO moldDO = moldService.getMold(id);
moldDO.setMachineId(createReqVO.getDeviceId());
moldDO.setMachineName(deviceLedger.getDeviceName());
moldDO.setStatus(0); // 在机 0 在库 1
moldService.updateMold(BeanUtils.toBean(moldDO, MoldSaveReqVO.class));
}
deviceLedger.setMoldId(createReqVO.getMoldId());
deviceLedgerService.updateDeviceLedger(BeanUtils.toBean(deviceLedger, DeviceLedgerSaveReqVO.class));
} else {
List<Long> lowerMoldId = Arrays.stream(createReqVO.getLowerMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
//下模
for (Long id : lowerMoldId) {
MoldDO moldDO = moldService.getMold(id);
moldDO.setMachineId(0L);
moldDO.setMachineName("");
moldDO.setStatus(3); // 在机 0 在途 3
moldService.updateMold(BeanUtils.toBean(moldDO, MoldSaveReqVO.class));
}
DeviceLedgerDO deviceLedger = deviceLedgerService.getDeviceLedger(createReqVO.getDeviceId());
createReqVO.setMoldId(Long.parseLong(deviceLedger.getMoldId()));
MoldDO moldDO = moldService.getMold(Long.parseLong(deviceLedger.getMoldId()));
moldDO.setMachineId(0L);
moldDO.setMachineName("");
moldDO.setStatus(3); // 在机 0 在库 1
moldService.updateMold(BeanUtils.toBean(moldDO, MoldSaveReqVO.class));
deviceLedger.setMoldId("0");
deviceLedger.setMoldId(createReqVO.getMoldId());
deviceLedgerService.updateDeviceLedger(BeanUtils.toBean(deviceLedger, DeviceLedgerSaveReqVO.class));
}
return success(moldOperateService.createMoldOperate(createReqVO));
@ -121,17 +140,18 @@ public class MoldOperateController {
// 管理员信息
Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
convertSet(pageResult.getList(), admin -> Long.parseLong(admin.getCreator())));
// 模具信息
Map<Long, MoldRespVO> moldMap = moldService.getMoldVOMap(
convertSet(pageResult.getList(), MoldOperateDO::getMoldId));
// // 模具信息
// Map<Long, MoldRespVO> moldMap = moldService.getMoldVOMap(
// convertSet(pageResult.getList(), MoldOperateDO::getMoldId));
// 设备台账
Map<Long, DeviceLedgerRespVO> deviceLedgerMap = deviceLedgerService.getDeviceLedgerVOMap(
convertSet(pageResult.getList(), MoldOperateDO::getDeviceId));
// Map<Long, DeviceLedgerRespVO> deviceLedgerMap = deviceLedgerService.getDeviceLedgerVOMap(
// convertSet(pageResult.getList(), MoldOperateDO::getDeviceId));
return success(BeanUtils.toBean(pageResult, MoldOperateRespVO.class,moldOperate -> {
MapUtils.findAndThen(userMap, Long.parseLong(moldOperate.getCreator()), user -> moldOperate.setCreatorName(user.getNickname()));
MapUtils.findAndThen(moldMap, moldOperate.getMoldId(), mold -> moldOperate.setMoldName(mold.getName()));
MapUtils.findAndThen(deviceLedgerMap, moldOperate.getDeviceId(), deviceLedger -> moldOperate.setDeviceName(deviceLedger.getDeviceName()));
// MapUtils.findAndThen(moldMap, moldOperate.getMoldId(), mold -> moldOperate.setMoldName(mold.getName()));
// MapUtils.findAndThen(deviceLedgerMap, moldOperate.getDeviceId(), deviceLedger -> moldOperate.setDeviceName(deviceLedger.getDeviceName()));
}));
}
@ -162,4 +182,13 @@ public class MoldOperateController {
}
@GetMapping("/getLowerMoldList")
@Operation(summary = "获得模具下模列表")
@Parameter(name = "id", description = "设备id", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('mes:mold-operate:query')")
public CommonResult<List<MoldDO>> getLowerMoldList(@RequestParam("id") Long id) {
List<MoldDO> moldDO = moldOperateService.getLowerMoldList(id);
return success(moldDO);
}
}

@ -16,7 +16,7 @@ public class MoldOperateSaveReqVO {
private String operateType;
@Schema(description = "关联模具id", example = "23041")
private Long moldId;
private String moldId;
@Schema(description = "关联设备id", example = "5057")
private Long deviceId;
@ -24,4 +24,7 @@ public class MoldOperateSaveReqVO {
@Schema(description = "备注", example = "随便")
private String remark;
@Schema(description = "下模模具id", example = "23041")
private String lowerMoldId;
}

@ -34,7 +34,7 @@ public class MoldOperateDO extends BaseDO {
/**
* id
*/
private Long moldId;
private String moldId;
/**
* id
*/
@ -44,4 +44,16 @@ public class MoldOperateDO extends BaseDO {
*/
private String remark;
/**
*
*/
private String moldName;
/**
*
*/
private String deviceName;
}

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.mes.service.criticalcomponent;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodelattribute.DeviceModelAttributeDO;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.validation.ValidationUtils;
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
@ -29,6 +30,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.dal.mysql.criticalcomponent.CriticalComponentMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODEL_ATTRIBUTE_POTIN_CODE_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
/**
@ -52,6 +54,18 @@ public class CriticalComponentServiceImpl implements CriticalComponentService {
@Override
public Long createCriticalComponent(CriticalComponentSaveReqVO createReqVO) {
//判断编码是否唯一
boolean exists = criticalComponentMapper.exists(
Wrappers.<CriticalComponentDO>lambdaQuery()
.eq(CriticalComponentDO::getCode, createReqVO.getCode()));
if (exists) {
throw exception(CRITICAL_COMPONENT_CODE_EXISTS);
}
// 插入
CriticalComponentDO criticalComponent = BeanUtils.toBean(createReqVO, CriticalComponentDO.class);
criticalComponentMapper.insert(criticalComponent);

@ -186,7 +186,7 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService {
//关键件列表
List<CriticalComponentDO> componentList = new ArrayList<>();
if (StringUtils.isNotBlank(deviceLedgerDO.getComponentId())) {
if (deviceLedgerDO != null && StringUtils.isNotBlank(deviceLedgerDO.getComponentId())) {
// 将逗号分隔的字符串转换为Long类型的List
List<Long> idList = Arrays.stream(deviceLedgerDO.getComponentId().split(","))
.map(String::trim) // 去除可能存在的空格
@ -203,7 +203,7 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService {
//模具列表
List<MoldDO> moldList = new ArrayList<>();
if (StringUtils.isNotBlank(deviceLedgerDO.getMoldId())) {
if (deviceLedgerDO != null && StringUtils.isNotBlank(deviceLedgerDO.getMoldId())) {
// 将逗号分隔的字符串转换为Long类型的List
List<Long> idList = Arrays.stream(deviceLedgerDO.getMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
@ -220,7 +220,7 @@ public class DeviceLedgerServiceImpl implements DeviceLedgerService {
//备件列表
List<ErpProductDO> beijianList = new ArrayList<>();
if (StringUtils.isNotBlank(deviceLedgerDO.getBeijianId())) {
if (deviceLedgerDO != null && StringUtils.isNotBlank(deviceLedgerDO.getBeijianId())) {
// 将逗号分隔的字符串转换为Long类型的List
List<Long> idList = Arrays.stream(deviceLedgerDO.getBeijianId().split(","))
.map(String::trim) // 去除可能存在的空格

@ -1,7 +1,6 @@
package cn.iocoder.yudao.module.mes.service.devicetype;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.iot.dal.dataobject.devicemodel.DeviceModelDO;
import cn.iocoder.yudao.module.mes.controller.admin.devicetype.vo.DeviceTypeTreeRespVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper;
@ -9,8 +8,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
@ -21,15 +19,13 @@ import java.util.stream.Collectors;
import cn.iocoder.yudao.module.mes.controller.admin.devicetype.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.devicetype.DeviceTypeDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.mes.dal.mysql.devicetype.DeviceTypeMapper;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODEL_CODE_EXISTS;
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
import static com.baomidou.mybatisplus.extension.toolkit.Db.list;
/**
* Service

@ -56,11 +56,12 @@ public class DvRepairServiceImpl implements DvRepairService {
createReqVO.setRepairCode(autoCodeUtil.genSerialCode("DVR_CODE",null));
} else {
//编码重复判断
Long count = dvRepairMapper.selectCount(new LambdaQueryWrapper<DvRepairDO>()
boolean exists = dvRepairMapper.exists(
Wrappers.<DvRepairDO>lambdaQuery()
.eq(DvRepairDO::getRepairCode, createReqVO.getRepairCode())
);
if (count > 0) {
if (exists) {
throw exception(DV_REPAIR_CODE_EXISTS);
}
}

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.mes.service.moldoperate;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.mes.controller.admin.moldoperate.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.moldoperate.MoldOperateDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -52,4 +54,7 @@ public interface MoldOperateService {
*/
PageResult<MoldOperateDO> getMoldOperatePage(MoldOperatePageReqVO pageReqVO);
List<MoldDO> getLowerMoldList(Long id);
}

@ -1,11 +1,19 @@
package cn.iocoder.yudao.module.mes.service.moldoperate;
import cn.iocoder.yudao.module.common.dal.dataobject.mold.MoldDO;
import cn.iocoder.yudao.module.common.dal.mysql.mold.MoldMapper;
import cn.iocoder.yudao.module.mes.dal.dataobject.deviceledger.DeviceLedgerDO;
import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper;
import jodd.util.StringUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
import cn.iocoder.yudao.module.mes.controller.admin.moldoperate.vo.*;
import cn.iocoder.yudao.module.mes.dal.dataobject.moldoperate.MoldOperateDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -29,10 +37,51 @@ public class MoldOperateServiceImpl implements MoldOperateService {
@Resource
private MoldOperateMapper moldOperateMapper;
@Resource
private DeviceLedgerMapper deviceLedgerMapper;
@Resource
private MoldMapper moldMapper;
@Override
public Long createMoldOperate(MoldOperateSaveReqVO createReqVO) {
// 插入
MoldOperateDO moldOperate = BeanUtils.toBean(createReqVO, MoldOperateDO.class);
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(createReqVO.getDeviceId());
moldOperate.setDeviceName(deviceLedgerDO.getDeviceName());
List<Long> idList;
if (createReqVO.getLowerMoldId()!=null){
idList = Arrays.stream(createReqVO.getLowerMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
}else {
idList = Arrays.stream(createReqVO.getMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
}
if (!idList.isEmpty()) {
StringBuilder moldNameBuilder = new StringBuilder();
for (Long id : idList) {
MoldDO moldDO = moldMapper.selectById(id);
if (moldDO != null && StringUtil.isNotBlank(moldDO.getName())) {
if (moldNameBuilder.length() > 0) {
moldNameBuilder.append(",");
}
moldNameBuilder.append(moldDO.getName());
}
}
moldOperate.setMoldName(moldNameBuilder.toString());
} else {
moldOperate.setMoldName("");
}
moldOperateMapper.insert(moldOperate);
// 返回
return moldOperate.getId();
@ -42,8 +91,34 @@ public class MoldOperateServiceImpl implements MoldOperateService {
public void updateMoldOperate(MoldOperateSaveReqVO updateReqVO) {
// 校验存在
validateMoldOperateExists(updateReqVO.getId());
// 更新
MoldOperateDO updateObj = BeanUtils.toBean(updateReqVO, MoldOperateDO.class);
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(updateReqVO.getDeviceId());
updateObj.setDeviceName(deviceLedgerDO.getDeviceName());
List<Long> idList = Arrays.stream(updateReqVO.getMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
if (!idList.isEmpty()) {
StringBuilder moldNameBuilder = new StringBuilder();
for (Long id : idList) {
MoldDO moldDO = moldMapper.selectById(id);
if (moldDO != null && StringUtil.isNotBlank(moldDO.getName())) {
if (moldNameBuilder.length() > 0) {
moldNameBuilder.append(",");
}
moldNameBuilder.append(moldDO.getName());
}
}
updateObj.setMoldName(moldNameBuilder.toString());
} else {
updateObj.setMoldName("");
}
moldOperateMapper.updateById(updateObj);
}
@ -71,4 +146,29 @@ public class MoldOperateServiceImpl implements MoldOperateService {
return moldOperateMapper.selectPage(pageReqVO);
}
@Override
public List<MoldDO> getLowerMoldList(Long id) {
List<MoldDO> moldDOList = new ArrayList<>();
DeviceLedgerDO deviceLedgerDO = deviceLedgerMapper.selectById(id);
if (StringUtil.isBlank(deviceLedgerDO.getMoldId())){
return new ArrayList<>();
}
List<Long> idList = Arrays.stream(deviceLedgerDO.getMoldId().split(","))
.map(String::trim) // 去除可能存在的空格
.map(Long::valueOf)
.collect(Collectors.toList());
for (Long moldId : idList) {
MoldDO moldDO = moldMapper.selectById(moldId);
if (moldDO != null){
moldDOList.add(moldDO);
}
}
return moldDOList;
}
}

@ -10,6 +10,7 @@ import cn.iocoder.yudao.module.mes.dal.mysql.deviceledger.DeviceLedgerMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@ -52,11 +53,11 @@ public class RepairTemsServiceImpl implements RepairTemsService {
@Override
public Long createRepairTems(RepairTemsSaveReqVO createReqVO) {
//编码重复判断
Long count = repairTemsMapper.selectCount(new LambdaQueryWrapper<RepairTemsDO>()
boolean exists = repairTemsMapper.exists(Wrappers.<RepairTemsDO>lambdaQuery()
.eq(RepairTemsDO::getSubjectCode, createReqVO.getSubjectCode())
);
if (count > 0) {
if (exists) {
throw exception(REPAIR_TEMS_CODE_EXISTS);
}

Loading…
Cancel
Save