Compare commits

...

8 Commits

@ -7,6 +7,7 @@ import com.op.system.api.factory.RemoteEnergyFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import java.util.Map;
@ -27,8 +28,8 @@ public interface RemoteEnergyService {
@PostMapping(value = "/record/dnbInstant/getNhEnergyDetail")
public R SyncNhEnergyDetail();
public R SyncNhEnergyDetail(@RequestHeader Map<String,String> header);
@PostMapping(value = "/record/dnbInstant/fixWwEnergyData",headers = {"poolName=ds_1000"})
public R syncFixWwEnergyData(@RequestBody Map<String ,String> map);
@PostMapping(value = "/record/dnbInstant/fixWwEnergyData")
public R syncFixWwEnergyData(@RequestBody Map<String ,String> map,@RequestHeader Map<String,String> header);
}

@ -164,6 +164,13 @@ public interface RemoteSapService {
@PostMapping("/sap/sapTransferPosting")
R sapTransferPosting(@RequestBody List<Map<String,Object>> list);
/**
*
* **/
@PostMapping("/sap/syncBaseProduct")
R syncBaseProduct(@RequestBody Map<String,Object> params);
}

@ -35,12 +35,12 @@ public class RemoteEnergyFallbackFactory implements FallbackFactory<RemoteEnergy
}
@Override
public R SyncNhEnergyDetail() {
public R SyncNhEnergyDetail(Map<String, String> header) {
return R.fail("同步电表实时数据失败:" + throwable.getMessage());
}
@Override
public R syncFixWwEnergyData(Map<String ,String> map) {
public R syncFixWwEnergyData(Map<String ,String> map, Map<String,String> header) {
return R.fail("修正威伟电表数据失败:" + throwable.getMessage());
}
};

@ -208,6 +208,16 @@ public class RemoteSapFallbackFactory implements FallbackFactory<RemoteSapServic
return R.fail("311转储过账" + throwable.getMessage());
}
/**
*
*
* @param params
**/
@Override
public R syncBaseProduct(Map<String, Object> params) {
return R.fail("手动同步物料失败" + throwable.getMessage());
}
};
}
}

@ -27,7 +27,6 @@ import com.op.device.mapper.*;
import com.op.system.api.RemoteOpenService;
import com.op.system.api.domain.SysNoticeGroup;
import com.op.system.api.domain.dto.WechartDTO;
import org.omg.CORBA.CompletionStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

@ -331,7 +331,14 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
resultMap.put("lastMonthEnd", now.withDayOfMonth(1).minusDays(1).with(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
// 去年的开始和结束时间
resultMap.put("lastYearStart", now.minusYears(1).withDayOfYear(1).with(LocalTime.MIN).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
resultMap.put("lastYearEnd", now.minusYears(1).withDayOfYear(lastYear.minusYears(1).lengthOfYear()).with(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
String lastYearEnd = now.minusYears(1)
// 修正用lastYear.lengthOfYear()获取去年的总天数,定位到去年最后一天
.withDayOfYear(lastYear.lengthOfYear())
// 设置为当天最后一刻
.with(LocalTime.MAX)
// 格式化为指定字符串(会自动截断纳秒,只保留到秒)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
resultMap.put("lastYearEnd", lastYearEnd);
// 去年当月的开始和结束时间
LocalDateTime nowNew = LocalDateTime.now();
LocalDate lastYearMonth = LocalDate.now().minusYears(1).withMonth(nowNew.getMonthValue());

@ -248,6 +248,7 @@ public class RecordDnbInstantServiceImpl implements IRecordDnbInstantService {
}
@Override
@DS("#header.poolName")
public void getNhEnergyDetail() {
Map<String,String> params = new HashMap<>();
params.put("dateType","mi15");
@ -322,10 +323,6 @@ public class RecordDnbInstantServiceImpl implements IRecordDnbInstantService {
}
}
DynamicDataSourceContextHolder.push("ds_1000");
try {
for (RecordDnbInstant item : list) {
BaseMonitorInfo temp = new BaseMonitorInfo();
temp.setConnCode(item.getMonitorId());
@ -335,9 +332,6 @@ public class RecordDnbInstantServiceImpl implements IRecordDnbInstantService {
recordDnbInstantMapper.insertRecordDnbInstant(item);
}
}
}finally {
DynamicDataSourceContextHolder.poll();
}
}

@ -0,0 +1,50 @@
package com.op.job.config;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Getter
public enum DbIdentityEnum {
// 小榄工厂
DS_1000("ds_1000", buildHeader("ds_1000")),
// 雅黛
DS_1010("ds_1010", buildHeader("ds_1010")),
// 重庆工厂
DS_1020("ds_1020", buildHeader("ds_1020")),
// 江西工厂
DS_1030("ds_1030", buildHeader("ds_1030")),
// 安徽工厂
DS_1040("ds_1040", buildHeader("ds_1040"));
// 数据库唯一标识(服务端路由依据)
private final String poolName;
// 该数据库的专属请求头Feign调用时传入
private final Map<String, String> dbHeader;
DbIdentityEnum(String poolName, Map<String, String> dbHeader) {
this.poolName = poolName;
this.dbHeader = dbHeader;
}
/**
*
*/
private static Map<String, String> buildHeader(String poolName) {
Map<String, String> header = new HashMap<>(3);
header.put("poolName", poolName);
return header;
}
/**
* 线
*/
public static Map<String, Map<String, String>> getAllDbHeaders() {
return Stream.of(values())
.collect(Collectors.toMap(DbIdentityEnum::getPoolName, DbIdentityEnum::getDbHeader));
}
}

@ -0,0 +1,40 @@
package com.op.job.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线
* 线
*/
@Configuration
public class MultiDbThreadPoolConfig {
/**
* 线
* /CPU
*/
@Bean("multiDbTaskExecutor")
public ThreadPoolTaskExecutor multiDbTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
int cpuCore = Runtime.getRuntime().availableProcessors();
int dbCount = DbIdentityEnum.values().length;
// 核心线程数:数据库数
executor.setCorePoolSize(Math.max(dbCount, cpuCore));
// 最大线程数:核心线程数*2
executor.setMaxPoolSize(Math.max(dbCount, cpuCore) * 2);
// 任务队列:数据库数*3
executor.setQueueCapacity(dbCount * 3);
// 线程名前缀:便于日志排查
executor.setThreadNamePrefix("multi-db-");
// 拒绝策略:调用线程执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化线程池
executor.initialize();
return executor;
}
}

@ -1,9 +1,11 @@
package com.op.job.task;
import com.op.job.util.MultiDbFeignExecutor;
import com.op.system.api.*;
import com.op.system.api.domain.sap.SapRouterQuery;
import com.op.system.api.domain.sap.SapShopOrderQuery;
import com.op.system.api.domain.sap.SapZmesGetMchb;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -14,6 +16,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
*
@ -21,6 +24,7 @@ import java.util.Map;
* @author OP
*/
@Component("ryTask")
@Slf4j
public class RyTask {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
@ -46,6 +50,9 @@ public class RyTask {
@Autowired
private RemoteEnergyService remoteEnergyService;
@Autowired
private MultiDbFeignExecutor multiDbFeignExecutor;
public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) {
System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
}
@ -271,7 +278,16 @@ public class RyTask {
/**********同步电实时数据*********/
public void SyncNhEnergyDetail(){
logger.info("++同步电实时数据+开始++getNhEnergyDetail+++++");
remoteEnergyService.SyncNhEnergyDetail();
multiDbFeignExecutor.execute("syncFixWwEnergyData", dbHeader -> {
try {
//每个数据库线程休眠1到5秒防止威伟电表接口限流
int randomMills = ThreadLocalRandom.current().nextInt(1000, 5001);
Thread.sleep(randomMills);
remoteEnergyService.SyncNhEnergyDetail(dbHeader);
}catch (Exception e){
log.info("任务执行出错");
}
});
}
@ -297,19 +313,24 @@ public class RyTask {
/**********修正威伟电表数据(有参)*********/
public void syncFixWwEnergyData(String beginDate,String endDate){
logger.info("+++修正威伟电表数据(有参)++syncFixWwEnergyData+++++");
multiDbFeignExecutor.execute("syncFixWwEnergyData", dbHeader -> {
Map<String ,String> map = new HashMap<>();
map.put("beginDate",beginDate);
map.put("endDate",endDate);
remoteEnergyService.syncFixWwEnergyData(map);
remoteEnergyService.syncFixWwEnergyData(map,dbHeader);
});
}
/** 修正威伟电表数据(无参) **/
public void syncFixWwEnergyData(){
logger.info("+++修正威伟电表数据(无参)++syncFixWwEnergyData+++++");
multiDbFeignExecutor.execute("syncFixWwEnergyData", dbHeader -> {
Map<String ,String> map = new HashMap<>();
map.put("beginDate","");
map.put("endDate","");
remoteEnergyService.syncFixWwEnergyData(map);
remoteEnergyService.syncFixWwEnergyData(map,dbHeader);
});
}
}

@ -0,0 +1,76 @@
package com.op.job.util;
import com.op.job.config.DbIdentityEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
/**
* Feign
* execute
* 线+++
*/
@Component
@Slf4j
public class MultiDbFeignExecutor {
@Autowired
@Qualifier("multiDbTaskExecutor")
private ThreadPoolTaskExecutor multiDbTaskExecutor;
/**
* 线Feign线
* @param taskName
* @param feignCall Feign=
*/
public void execute(String taskName, FeignDbCall feignCall) {
// 1. 获取所有数据库的专属请求头一个库一个独立Map线程安全
Map<String, Map<String, String>> allDbHeaders = DbIdentityEnum.getAllDbHeaders();
if (allDbHeaders.isEmpty()) {
log.warn("【多库执行-{}】无配置的数据库,直接返回", taskName);
return;
}
log.info("【多库执行-{}】开始并行执行,数据库数量:{}", taskName, allDbHeaders.size());
// 2. 多线程并行执行:每个数据库一个独立线程,异常隔离
allDbHeaders.entrySet().stream()
.map(entry -> {
String dbId = entry.getKey();
Map<String, String> dbHeader = entry.getValue();
// 提交异步任务,绑定专属线程池
return CompletableFuture.runAsync(() -> {
try {
log.info("【多库执行-{}】开始执行数据库:{}", taskName, dbId);
// 执行Feign调用传入当前数据库的专属请求头
feignCall.call(dbHeader);
log.info("【多库执行-{}】数据库{}执行成功", taskName, dbId);
} catch (Exception e) {
// 单个数据库执行异常,隔离处理,不影响其他库
log.error("【多库执行-{}】数据库{}执行失败,异常原因:{}",
taskName, dbId, e.getMessage(), e);
}
}, multiDbTaskExecutor);
})
.collect(Collectors.toList())
// 3. 等待所有数据库执行完成(保证定时任务执行完整性)
.forEach(CompletableFuture::join);
log.info("【多库执行-{}】所有数据库执行完毕,总库数:{}", taskName, allDbHeaders.size());
}
/**
* Feign
* MapFeign
*/
@FunctionalInterface
public interface FeignDbCall {
void call(Map<String, String> dbHeader);
}
}

@ -108,4 +108,12 @@ public class MesBoardController extends BaseController {
}
return success(iMesBoradService.getHFxlInfo(mesBoard));
}
/**获取包装产线看板数据*/
@GetMapping("/getProductionLineData")
public AjaxResult getProductionLineData() {
return success(iMesBoradService.getProductionLineData());
}
}

@ -0,0 +1,26 @@
package com.op.mes.controller;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* remark
*
* @author 019117
* @date
*/
@RestController
@RequestMapping("/mesProductLine")
@RequiredArgsConstructor
public class MesProductLineController {
/**
* 线
* **/
}

@ -123,4 +123,6 @@ public interface MesMapper {
List<String> getproductLineList();
List<Map<String, Object>> getProductionLineData();
}

@ -24,4 +24,6 @@ public interface IMesBoradService {
public List<BoardDTO> getHFxlInfo(BoardDTO mesBoard);
public Map getProductionNumberPLC(BoardDTO mesBoard);
List<Map<String, Object>> getProductionLineData();
}

@ -284,4 +284,10 @@ public class MesBoradServiceImpl implements IMesBoradService {
}
}
@Override
@DS("#header.poolName")
public List<Map<String, Object>> getProductionLineData() {
return mesMapper.getProductionLineData();
}
}

@ -552,4 +552,49 @@
product_date = CONVERT ( VARCHAR ( 10 ), GETDATE( ), 120 )
</select>
<select id="getProductionLineData" resultType="java.util.Map">
SELECT
STRING_AGG ( t.productName, ',' ) WITHIN GROUP ( ORDER BY t.workorderCode ASC ) productName,
equ.equipment_name equipmentName,
SUM ( t.quantitySplit ) planTotal,
ISNULL(NULLIF(SUM ( t2.qty_total), 0), SUM ( t1.quantityProduced )) completTotal
FROM
(
SELECT
pow.workorder_code workorderCode,
pow.product_name productName,
SUM ( powb.batch_quantity ) quantitySplit,
pow.workorder_name
FROM
pro_order_workorder pow
LEFT JOIN pro_order_workorder_batch powb ON powb.workorder_id = pow.workorder_id
WHERE
pow.del_flag = '0'
AND CONVERT ( VARCHAR ( 10 ), pow.product_date, 120 ) = CONVERT ( VARCHAR ( 10 ), GETDATE( ), 120 )
AND pow.parent_order = '0'
AND powb.del_flag = '0'
AND pow.workorder_name IS NOT NULL
GROUP BY
pow.workorder_code,
pow.product_name,
pow.workorder_name
) t
LEFT JOIN (
SELECT
workorder_code,
SUM ( quantity_feedback ) quantityProduced
FROM
mes_report_work
WHERE
CONVERT ( VARCHAR ( 10 ), feedback_time, 120 ) = CONVERT ( VARCHAR ( 10 ), GETDATE( ), 120 )
AND del_flag = '0'
GROUP BY
workorder_code
) t1 ON t.workorderCode = t1.workorder_code
LEFT JOIN ( SELECT line_code, workorder_code, qty_build, qty_total FROM pro_workbatch_inwork ) t2 ON t.workorderCode = t2.workorder_code
LEFT JOIN base_equipment equ ON t.workorder_name = equ.equipment_code
GROUP BY
equ.equipment_name,t.workorder_name
</select>
</mapper>

@ -1776,6 +1776,7 @@ public class QcStaticTableServiceImpl implements IQcStaticTableService {
@DS("#header.poolName")
public List<Map<String,String>> getMonthOfDataDefectV2(QcStaticTable qcStaticTable) {
List<String> bpDefects = qcStaticTableMapper.getBpDefects(qcStaticTable);
bpDefects.add("其他");
List<QcCheckTaskDefect> list = qcStaticTableMapper.getBPDefectList(qcStaticTable);
List<Map<String,String>> result = new ArrayList<>();
for (String defect : bpDefects){

@ -1414,7 +1414,7 @@
<select id="getBPDefectList" resultType="com.op.quality.domain.QcCheckTaskDefect">
SELECT
tc.class_name defectSubclass,
ISNULL(tc.class_name,'其他') defectSubclass,
FORMAT ( qct.create_time, 'yyyy-MM-dd' ) attr1,
SUM(td.noOk_quality) attr2,
SUM(qct.sample_quality) attr3

@ -675,4 +675,13 @@ public class SapController extends BaseController {
public R sapTransferPosting(@RequestBody List<Map<String, Object>> list) {
return sapWmsService.sapTransferPosting(list);
}
/**
*
* **/
@PostMapping("/syncBaseProduct")
@Log(title = "手动同步物料", businessType = BusinessType.SAP)
public R syncBaseProduct(@RequestBody SapItemQuery params) {
return sapItemSyncService.itemSync(params);
}
}

@ -2,6 +2,7 @@ package com.op.wms.controller;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
@ -111,4 +112,18 @@ public class BaseProductController extends BaseController {
public AjaxResult remove(@PathVariable String[] productIds) {
return toAjax(baseProductService.deleteBaseProductByProductIds(productIds));
}
/**
*
*/
@Log(title = "手动同步物料", businessType = BusinessType.SAP)
@PostMapping("/sync")
public AjaxResult sync(@RequestBody Map<String,Object> params) {
baseProductService.syncBaseProduct(params);
return success();
}
}

@ -1,6 +1,7 @@
package com.op.wms.service;
import java.util.List;
import java.util.Map;
import com.op.wms.domain.BaseProduct;
@ -64,4 +65,6 @@ public interface IBaseProductService {
boolean checkNameUnique(BaseProduct baseProduct);
public BaseProduct selectBaseProductByProductCode(String productCode);
void syncBaseProduct( Map<String,Object> params);
}

@ -1,10 +1,13 @@
package com.op.wms.service.impl;
import java.util.List;
import java.util.Map;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.op.common.core.domain.R;
import com.op.common.core.utils.DateUtils;
import com.op.common.security.utils.SecurityUtils;
import com.op.system.api.RemoteSapService;
import com.op.wms.domain.BaseTeamT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -23,6 +26,9 @@ public class BaseProductServiceImpl implements IBaseProductService {
@Autowired
private BaseProductMapper baseProductMapper;
@Autowired
private RemoteSapService remoteSapService;
/**
*
*
@ -138,4 +144,12 @@ public class BaseProductServiceImpl implements IBaseProductService {
public BaseProduct selectBaseProductByProductCode(String productCode) {
return baseProductMapper.selectBaseProductByProductCode(productCode);
}
@Override
public void syncBaseProduct( Map<String,Object> params) {
R result = remoteSapService.syncBaseProduct(params);
if (result.getCode() != 200){
throw new RuntimeException("同步失败:"+result.getMsg());
}
}
}

@ -2254,67 +2254,5 @@
</update>
<select id="getStockAreaEntryList" resultType="com.op.wms.domain.WmsStockAreaEntry" parameterType="com.op.wms.domain.WmsStockAreaEntry">
SELECT
CONVERT(VARCHAR, pow.product_date, 23) productionDate,
SUBSTRING(pow.workorder_code_sap, 4, 10) workOrderCode,
SUBSTRING(pow.product_code, 8,11) materialCode,
pow.product_name materialName,
CASE
WHEN LEN(powb.batch_code) = 24 THEN SUBSTRING(powb.batch_code, 13, 10)
WHEN LEN(powb.batch_code) <![CDATA[ < ]]> 24 THEN powb.batch_code
WHEN LEN(powb.batch_code) > 24 THEN CONVERT(VARCHAR(8), pow.create_time, 112)
ELSE ''
END batchCode
FROM pro_order_workorder pow
LEFT JOIN pro_order_workorder_batch powb ON pow.workorder_id = powb.workorder_id
WHERE powb.del_flag = '0' AND pow.product_code like '00000001%' and pow.parent_order = '0'
<if test="beginDate != null ">and CONVERT(varchar(10),pow.product_date, 120) >= '${beginDate}'</if>
<if test="endDate != null ">and '${endDate}' >= CONVERT(varchar(10),pow.product_date, 120)</if>
<if test="workOrderCode != null and workOrderCode != ''">and pow.workorder_code like concat('%', #{workOrderCode}, '%')</if>
<if test="status != null and status != ''">and pow.status = #{status}</if>
<if test="materialCode != null and materialCode != ''">and pow.product_code like concat('%', #{materialCode},'%')</if>
ORDER BY pow.workorder_code_sap, powb.batch_code
</select>
<select id="batchCheckDuplication" resultType="com.op.wms.domain.WmsStockAreaEntry" parameterType="list">
SELECT material_code materialCode, batch_code batchCode, factory_code factoryCode, area_code areaCode
FROM wms_material_entry
WHERE CONCAT(material_code, batch_code, factory_code, area_code) IN
<foreach collection="list" item="item" open="(" separator="," close=")">
CONCAT(#{item.materialCode}, #{item.batchCode}, #{item.factoryCode}, #{item.areaCode})
</foreach>
</select>
<insert id="batchInsertMaterialEntry" parameterType="list">
INSERT INTO wms_material_entry (
work_order_code,
material_code,
batch_code,
factory_code,
location,
area_code,
status,
create_time,
create_by
)
VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.workOrderCode},
#{item.materialCode},
#{item.batchCode},
#{item.factoryCode},
#{item.location},
#{item.areaCode},
#{item.status},
GETDATE(),
#{item.createBy}
)
</foreach>
</insert>
</mapper>

Loading…
Cancel
Save