| 
					
				 | 
			
			
				@@ -0,0 +1,206 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+package org.springblade.manager.service.impl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.hutool.json.JSONObject; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import cn.hutool.json.JSONUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.alibaba.nacos.common.utils.MD5Utils; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.baomidou.mybatisplus.core.toolkit.Wrappers; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.baomidou.mybatisplus.extension.plugins.pagination.Page; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.common.utils.SnowFlakeUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.core.oss.model.BladeFile; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.core.tool.utils.BeanUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.core.tool.utils.CollectionUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.core.tool.utils.StringUtil; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.dto.ProfilerOffsetDTO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.dto.ProfilerOffsetResultDTO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.entity.ProfilerData; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.entity.ProfilerOffset; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.entity.ProfilerStandardSectionBean; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.entity.profiler.ProfilerResult; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.entity.profiler.ProfilerSaveDTO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.service.ProfilerDataService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.service.ProfilerOffsetService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.mapper.ProfilerOffsetMapper; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.manager.service.ProfilerStandardSectionBeanService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springblade.resource.feign.NewIOSSClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.stereotype.Service; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.transaction.annotation.Transactional; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import org.springframework.web.multipart.MultipartFile; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import javax.annotation.Resource; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.time.Instant; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.Collections; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+import java.util.List; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+/** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @author LHB 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @description 针对表【q_profiler_offset(断面仪-基础信息+测量者信息)】的数据库操作Service实现 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ * @createDate 2025-10-27 15:58:56 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+@Service 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+public class ProfilerOffsetServiceImpl extends ServiceImpl<ProfilerOffsetMapper, ProfilerOffset> 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        implements ProfilerOffsetService { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //第三方的appKey 固定值 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private final static String APP_KEY = "QDM123"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    //第三方密钥 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private final static String APP_SECRET = "MDc1YWI4OTMtY2M0NC00NDViLTlkZmUtYzAzZTVmZTUxMmE1"; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    // 时间戳有效期(秒),防止重放攻击 // 30分钟 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static final long TIMESTAMP_EXPIRE = 1800; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private NewIOSSClient newIOSSClient; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ProfilerDataService dataService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Resource 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private ProfilerStandardSectionBeanService beanService; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Transactional(rollbackFor = Exception.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public ProfilerResult save(ProfilerSaveDTO save, MultipartFile file) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!save.getAppKey().equals(APP_KEY)) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return ProfilerResult.error("10006", "appKey错误", ""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String s = MD5Utils.md5Hex(APP_KEY +  APP_SECRET + save.getTimestamp(),  "UTF-8"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (!s.equals(save.getSign())) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return ProfilerResult.error("10007", "sign错误", ""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(!isValidTimestamp(save.getTimestamp())){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return ProfilerResult.error("10008","签名验证失败:timeTicks的时间和当前时间必须小于30分钟",""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //主键id 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        Long id = SnowFlakeUtil.getId(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //断面仪测量设备编码或名称 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        String deviceCode = save.getDeviceCode(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //字符串转json 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        JSONObject jsonObject = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            jsonObject = JSONUtil.parseObj(save.getData()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (Exception e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return ProfilerResult.error("10009","data参数格式错误",""); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //获取基础信息 + 测量者信息 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ProfilerOffset offset = jsonObject.getBean("offset", ProfilerOffset.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(offset == null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset = new ProfilerOffset(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        offset.setId(id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        offset.setDeviceCode(deviceCode); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ProfilerOffset info = jsonObject.getBean("info", ProfilerOffset.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //把测量者信息赋值给基础信息对象 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(info != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setChannelName(info.getChannelName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setConstructionUnit(info.getConstructionUnit()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setDate(info.getDate()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setNameOfProject(info.getNameOfProject()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setUserName(info.getUserName()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setMileageNumber(info.getMileageNumber()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //获取标准断面数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        JSONObject mStandardSectionDataBeanList = jsonObject.getJSONObject("standardSectionBean"); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<ProfilerStandardSectionBean> standardSectionBean = null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(mStandardSectionDataBeanList != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            standardSectionBean = mStandardSectionDataBeanList.getBeanList("mStandardSectionDataBeanList", ProfilerStandardSectionBean.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(standardSectionBean != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                standardSectionBean.forEach(f ->{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    f.setId(SnowFlakeUtil.getId()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                    f.setOffsetId(id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //获取测量数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<ProfilerData> data = jsonObject.getBeanList("data", ProfilerData.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(data != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            data.forEach(f -> { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                f.setId(SnowFlakeUtil.getId()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                f.setOffsetId(id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            }); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //上传文件 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if (file != null && !file.isEmpty() && file.getSize() > 0) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            //获取文件名称后缀 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            BladeFile bladeFile = this.newIOSSClient.uploadFileByInputStream(file); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            offset.setFileUrl(bladeFile.getLink()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        //保存数据 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        baseMapper.insert(offset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(CollectionUtil.isNotEmpty(standardSectionBean)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            beanService.saveBatch(standardSectionBean); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(CollectionUtil.isNotEmpty(data)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dataService.saveBatch(data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return ProfilerResult.success(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    /** 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 验证时间戳有效性 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @param timestamp 时间戳字符串 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     * @return 是否有效 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+     */ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    private static boolean isValidTimestamp(Long timestamp) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        try { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            long currentTs = Instant.now().getEpochSecond(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            // 检查时间戳是否在有效期内(前后5分钟) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return Math.abs(currentTs - timestamp) <= TIMESTAMP_EXPIRE; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } catch (NumberFormatException e) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return false; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public ProfilerOffsetResultDTO getOne(Long id) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ProfilerOffset byId = this.getById(id); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(byId != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            ProfilerOffsetResultDTO resultDTO = BeanUtil.copyProperties(byId, ProfilerOffsetResultDTO.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            if(resultDTO != null){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                List<ProfilerStandardSectionBean> list = beanService.list(Wrappers.<ProfilerStandardSectionBean>lambdaQuery().eq(ProfilerStandardSectionBean::getOffsetId, id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                List<ProfilerData> list1 = dataService.list(Wrappers.<ProfilerData>lambdaQuery().eq(ProfilerData::getOffsetId, id)); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                resultDTO.setSectionBeans(list); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                resultDTO.setData(list1); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            return resultDTO; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return null; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Transactional(rollbackFor = Exception.class) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public boolean edit(ProfilerOffsetResultDTO offset) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        ProfilerOffset qProfilerOffset = BeanUtil.copyProperties(offset, ProfilerOffset.class); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        boolean update = this.updateById(qProfilerOffset); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<ProfilerStandardSectionBean> sectionBeans = offset.getSectionBeans(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(CollectionUtil.isNotEmpty(sectionBeans)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            beanService.updateBatchById(sectionBeans); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        List<ProfilerData> data = offset.getData(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        if(CollectionUtil.isNotEmpty(data)){ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+            dataService.updateBatchById(data); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return update; 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public Page<ProfilerOffset> getPage(ProfilerOffsetDTO offset) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        QueryWrapper<ProfilerOffset> qProfilerOffsetQueryWrapper = new QueryWrapper<>(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        qProfilerOffsetQueryWrapper.lambda() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .eq(StringUtil.isNotBlank(offset.getUserName()), ProfilerOffset::getUserName, offset.getUserName()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .eq(StringUtil.isNotBlank(offset.getBackBreak()), ProfilerOffset::getBackBreak, offset.getBackBreak()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .ge(StringUtil.isNotBlank(offset.getStartTime()), ProfilerOffset::getDate, offset.getStartTime()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+                .le(StringUtil.isNotBlank(offset.getEndTime()), ProfilerOffset::getDate, offset.getEndTime()); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return baseMapper.selectPage(new Page<>(offset.getCurrent(), offset.getSize()),qProfilerOffsetQueryWrapper); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    @Override 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    public List<String> getListUserName() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+        return baseMapper.getListUserName(); 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+    } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 |