zhoulisky 7 months ago
parent
commit
f6ec56ea56

+ 15 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/config/RestTemplateConfig.java

@@ -0,0 +1,15 @@
+package org.sky.scientific.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+	@Bean
+	public RestTemplate restTemplate() {
+		return new RestTemplate();
+	}
+
+}

+ 17 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/controller/XmTechnicianHoursController.java

@@ -13,9 +13,11 @@ import org.sky.core.mp.support.Condition;
 import org.sky.core.mp.support.Query;
 import org.sky.core.tool.api.R;
 import org.sky.core.tool.utils.Func;
+import org.sky.scientific.pojo.dto.HoursSyncDto;
 import org.sky.scientific.pojo.dto.TechnicianDTO;
 import org.sky.scientific.pojo.vo.TechnicianHoursMonthlyVO;
 import org.sky.scientific.pojo.vo.XmTechnicianHoursVO;
+import org.sky.scientific.service.IHoursSyncService;
 import org.sky.scientific.service.IXmTechnicianHoursService;
 import org.sky.scientific.utils.ExportUtil;
 import org.springframework.web.bind.annotation.*;
@@ -37,6 +39,7 @@ import java.util.List;
 public class XmTechnicianHoursController extends KdController {
 
 	private final IXmTechnicianHoursService service;
+	private final IHoursSyncService hoursSyncService;
 
 	@GetMapping("/page")
 	@ApiOperationSupport(order = 1)
@@ -101,4 +104,18 @@ public class XmTechnicianHoursController extends KdController {
 		service.exportMeiyueyanfagongshifenpeibiao(response, dto);
 	}
 
+	@PostMapping("/sync")
+	@ApiOperationSupport(order = 40)
+	@Operation(summary = "同步至工时系统")
+	public R<Boolean> sync(@RequestBody HoursSyncDto dto){
+		return R.status(hoursSyncService.syncHoursData(dto));
+	}
+
+	@PostMapping("accept")
+	@ApiOperationSupport(order = 50)
+	@Operation(summary = "同步至本系统")
+	public R<Boolean> acceptRdData(@RequestBody HoursSyncDto dto){
+		return R.status(hoursSyncService.acceptRdData(dto));
+	}
+
 }

+ 20 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IHoursSyncService.java

@@ -0,0 +1,20 @@
+package org.sky.scientific.service;
+
+import org.sky.scientific.pojo.dto.HoursSyncDto;
+
+public interface IHoursSyncService {
+
+	/**
+	 * 同步至工时系统
+	 * @param dto
+	 * @return
+	 */
+	boolean syncHoursData(HoursSyncDto dto);
+
+	/**
+	 * 同步至本系统
+	 * @param dto
+	 * @return
+	 */
+	boolean acceptRdData(HoursSyncDto dto);
+}

+ 1 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/IXmTechnicianHoursService.java

@@ -79,4 +79,5 @@ public interface IXmTechnicianHoursService extends BaseService<XmTechnicianHours
 	 * @param dto
 	 */
 	void exportMeiyueyanfagongshifenpeibiao(HttpServletResponse response, TechnicianDTO dto);
+
 }

+ 298 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/HoursSyncServiceImpl.java

@@ -0,0 +1,298 @@
+package org.sky.scientific.service.impl;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.sky.core.log.exception.ServiceException;
+import org.sky.core.secure.utils.SecureUtil;
+import org.sky.core.tool.api.R;
+import org.sky.core.tool.utils.DateUtil;
+import org.sky.core.tool.utils.Func;
+import org.sky.scientific.mapper.TechnicianMapper;
+import org.sky.scientific.mapper.XmMapper;
+import org.sky.scientific.mapper.XmTechnicianHoursMapper;
+import org.sky.scientific.pojo.dto.HoursSyncDto;
+import org.sky.scientific.pojo.entity.TechnicianEntity;
+import org.sky.scientific.pojo.entity.XmTechnicianHours;
+import org.sky.scientific.pojo.vo.XmVO;
+import org.sky.scientific.service.IHoursSyncService;
+import org.sky.system.feign.ISysClient;
+import org.sky.system.pojo.entity.Tenant;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.util.UriComponentsBuilder;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Data
+@Slf4j
+@Service
+@AllArgsConstructor
+public class HoursSyncServiceImpl implements IHoursSyncService {
+
+	private final XmTechnicianHoursMapper hoursMapper;
+	private final RestTemplate restTemplate;
+	private final ISysClient sysClient;
+	private final XmMapper xmMapper;
+	private final TechnicianMapper technicianMapper;
+	private static final String BASE_URL = "https://yanfa.jishutao.com/prod-api";
+	private static final String URL_LOGIN = BASE_URL + "/login";
+	private static final String URL_SYNC_HOURS = BASE_URL + "/api/project/pushCompanyData";
+	private static final String URL_ACCEPT_HOURS = BASE_URL + "/api/project/getCompanyClock";
+
+	private static final String HEAD_AUTHORIZATION = "Authorization";
+	private static final String USERNAME = "yandongli";
+	private static final String PASSWORD = "123456";
+	private static final Integer BATCH_SIZE = 100;
+
+	@Override
+	public boolean syncHoursData(HoursSyncDto dto) {
+		//先登录
+		String token = this.login();
+		if (token != null) {
+			JSONObject reqBody = getBasicInfo(dto.getYearAndMonth());
+
+			List<JSONObject> hoursList = hoursMapper.selectListForSync(dto.getYearAndMonth());
+			List<JSONObject> rdList = new ArrayList<>();
+			for (JSONObject hours : hoursList) {
+				JSONObject data = new JSONObject();
+				data.put("projectNumber", hours.getString("xmbh"));
+				data.put("adminKyId", SecureUtil.getTenantId() + "_" + hours.getString("unicode"));
+				data.put("recordTime", DateUtil.format(DateUtil.parse(hours.getString("workDate"), DateUtil.PATTERN_YYYYMMDD), DateUtil.PATTERN_DATE));
+				data.put("duration", hours.getString("workHours"));
+				rdList.add(data);
+			}
+			reqBody.put("usci", SecureUtil.getTenantId());
+			reqBody.put("rdList", rdList);
+			log.info("同步至工时系统:{}", JSON.toJSONString(reqBody));
+			HttpHeaders headers = new HttpHeaders();
+			headers.setContentType(MediaType.APPLICATION_JSON);
+			headers.add(HEAD_AUTHORIZATION, token);
+			HttpEntity<JSONObject> request = new HttpEntity<>(reqBody, headers);
+			ResponseEntity<String> response = restTemplate.exchange(URL_SYNC_HOURS, HttpMethod.POST, request, String.class);
+			if (response.getStatusCode().is2xxSuccessful()) {
+				JSONObject resp = JSONObject.parseObject(response.getBody());
+				assert resp != null;
+				Integer code = resp.getInteger("code");
+				if (code == 200) {
+					log.info("成功同步至工时系统");
+				} else {
+					log.error("同步至工时系统失败:{}", resp.getString("msg"));
+					throw new ServiceException("同步至工时系统失败:" + resp.getString("msg"));
+				}
+			} else {
+				throw new ServiceException("同步至工时系统失败:" + response.getStatusCode());
+			}
+		}
+		return true;
+	}
+
+	private JSONObject getBasicInfo(String yearAndMonth) {
+		JSONObject reqBody = new JSONObject();
+
+		List<JSONObject> listDep = new ArrayList<>();
+		JSONObject dep = new JSONObject();
+		R<Tenant> tenant = sysClient.getTenant(SecureUtil.getTenantId());
+		if (tenant.isSuccess()) {
+			dep.put("kyId", String.valueOf(tenant.getData().getId()));
+			dep.put("deptName", tenant.getData().getTenantName());
+			dep.put("kySuperId", null);
+		}
+		dep.put("usci", SecureUtil.getTenantId());
+		listDep.add(dep);
+
+		List<JSONObject> listUser = new ArrayList<>();
+		List<JSONObject> hoursList = hoursMapper.selectListForSync(yearAndMonth);
+		if (Func.isEmpty(hoursList)) {
+			throw new ServiceException("无数据可同步");
+		}
+		List<String> unicodeList = hoursList.stream().map(rd -> rd.getString("unicode")).distinct().toList();
+		for (String unicode : unicodeList) {
+			JSONObject user = new JSONObject();
+			user.put("kyDeptId", dep.get("kyId"));
+			user.put("userName", SecureUtil.getTenantId() + "_" + unicode);
+			TechnicianEntity dbTechnician = technicianMapper.selectByUnicodeAndYearAndMonth(unicode, yearAndMonth);
+			if (Func.notNull(dbTechnician)) {
+				user.put("nickName", dbTechnician.getName());
+			}
+			user.put("kyId", user.getString("userName"));
+			user.put("kySuperId", null);
+			listUser.add(user);
+		}
+
+		List<Long> xmIdList = hoursList.stream().map(rd -> rd.getLong("xmId")).distinct().toList();
+		List<XmVO> xmList = xmMapper.selectByXmIdList(xmIdList);
+		Map<Long, List<String>> mapByXmId = hoursList.stream().collect(Collectors.groupingBy(rd -> rd.getLong("xmId"), Collectors.mapping(rd -> rd.getString("unicode"), Collectors.toList())));
+
+		List<JSONObject> listUserProject = new ArrayList<>();
+		for (XmVO xmVO : xmList) {
+			JSONObject data = new JSONObject();
+			data.put("projectName", xmVO.getXmmc());
+			TechnicianEntity dbTechnician = technicianMapper.selectById(xmVO.getXmfzr());
+			if (Func.notNull(dbTechnician)) {
+				String username = SecureUtil.getTenantId() + "_" + dbTechnician.getUnicode();
+				if (listUser.stream().noneMatch(user -> user.getString("userName").equals(username))) {
+					JSONObject user = new JSONObject();
+					user.put("kyDeptId", dep.get("kyId"));
+					user.put("userName", username);
+					user.put("nickName", dbTechnician.getName());
+					user.put("kyId", username);
+					user.put("kySuperId", null);
+					listUser.add(user);
+				}
+				data.put("aid", username);
+			}
+
+			data.put("projectNumber", xmVO.getXmbh());
+			data.put("startTime", DateUtil.format(xmVO.getXmkssj(), DateUtil.PATTERN_DATE));
+			data.put("endTime", DateUtil.format(xmVO.getXmjssj(), DateUtil.PATTERN_DATE));
+			data.put("projectYear", DateUtil.format(xmVO.getXmkssj(), DateUtil.PATTERN_YYYY));
+			data.put("createYear", DateUtil.format(xmVO.getCreateTime(), DateUtil.PATTERN_YYYY));
+			List<String> unicodes = mapByXmId.get(xmVO.getId());
+			data.put("staffIds", unicodes.stream().distinct().map(unicode -> SecureUtil.getTenantId() + "_" + unicode).collect(Collectors.joining(",")));
+			listUserProject.add(data);
+		}
+
+		reqBody.put("listDep", listDep);
+		reqBody.put("listUser", listUser);
+		reqBody.put("listUserProject", listUserProject);
+
+		return reqBody;
+	}
+
+	@Override
+	public boolean acceptRdData(HoursSyncDto dto) {
+		//先登录
+		String token = this.login();
+		if (token != null) {
+			String url = UriComponentsBuilder.fromHttpUrl(URL_ACCEPT_HOURS)
+				.queryParam("usci", SecureUtil.getTenantId())
+				.queryParam("year", Integer.valueOf(dto.getYearAndMonth().substring(0, 4)))
+				.queryParam("month", Integer.valueOf(dto.getYearAndMonth().substring(4, 6))).toUriString();
+			HttpHeaders headers = new HttpHeaders();
+			headers.setContentType(MediaType.APPLICATION_JSON);
+			headers.add(HEAD_AUTHORIZATION, token);
+			HttpEntity<JSONObject> request = new HttpEntity<>(headers);
+			ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
+			if (response.getStatusCode().is2xxSuccessful()) {
+				JSONObject resp = JSONObject.parseObject(response.getBody());
+				assert resp != null;
+				Integer code = resp.getInteger("code");
+				if (code == 200) {
+					JSONObject data = resp.getJSONObject("data");
+					JSONArray rdList = data.getJSONArray("rdList");
+					Map<String, Long> xmMap = new HashMap<>();
+
+					List<JSONObject> dbHoursList = hoursMapper.selectListForSync(dto.getYearAndMonth());
+					List<String> identifierList = dbHoursList.stream().map(t ->
+						t.getString("tenantId") + ":" + t.getString("xmId") + ":" + t.getString("unicode") + ":" + t.getString("workDate")).toList();
+					List<XmTechnicianHours> insertList = new ArrayList<>();
+					List<XmTechnicianHours> updateList = new ArrayList<>();
+					for (Object o : rdList) {
+						JSONObject rd = (JSONObject) o;
+						Double duration = rd.getDouble("duration");
+
+						String adminKyId = rd.getString("adminKyId");
+						List<String> tenantAndUnicode = Arrays.asList(adminKyId.split("_"));
+
+						String recordTime = rd.getString("recordTime");
+						recordTime = DateUtil.format(DateUtil.parse(recordTime, DateUtil.PATTERN_YYYY_MM_DD), DateUtil.PATTERN_YYYYMMDD);
+
+						String projectNumber = rd.getString("projectNumber");
+						if (!xmMap.containsKey(projectNumber)) {
+							Long xmId = xmMapper.getXmIdByXmbh(projectNumber);
+							if (xmId == null) {
+								xmId = 0L;
+							}
+							xmMap.put(projectNumber, xmId);
+						}
+						Long xmId = xmMap.get(projectNumber);
+						if (xmId <= 0L) {
+							continue;
+						}
+						String identifier = SecureUtil.getTenantId() + ":" + xmId + ":" + tenantAndUnicode.get(1) + ":" + recordTime;
+						if (identifierList.contains(identifier)) {
+							//现有的,做修改
+							XmTechnicianHours updateEntity = new XmTechnicianHours();
+							updateEntity.setTenantId(SecureUtil.getTenantId());
+							updateEntity.setXmId(xmId);
+							updateEntity.setUnicode(tenantAndUnicode.get(1));
+							updateEntity.setWorkDate(recordTime);
+							updateEntity.setWorkHours(duration);
+							updateList.add(updateEntity);
+						} else {
+							//新的,做插入
+							XmTechnicianHours insertEntity = new XmTechnicianHours();
+							insertEntity.setTenantId(SecureUtil.getTenantId());
+							insertEntity.setXmId(xmId);
+							insertEntity.setUnicode(tenantAndUnicode.get(1));
+							insertEntity.setWorkDate(recordTime);
+							insertEntity.setWorkHours(duration);
+							insertList.add(insertEntity);
+						}
+						if (Func.isNotEmpty(insertList) && insertList.size() % BATCH_SIZE == 0) {
+							hoursMapper.insert(insertList);
+							insertList.clear();
+						}
+						if (Func.isNotEmpty(updateList) && updateList.size() % BATCH_SIZE == 0) {
+							hoursMapper.batchUpdateHours(updateList);
+							updateList.clear();
+						}
+					}
+					if (Func.isNotEmpty(insertList)) {
+						hoursMapper.insert(insertList);
+					}
+					if (Func.isNotEmpty(updateList)) {
+						hoursMapper.batchUpdateHours(updateList);
+					}
+					log.info("同步至本系统,响应数据:{}", data);
+				} else {
+					log.error("同步至本系统失败:{}", resp.getString("msg"));
+					throw new ServiceException("同步至本系统失败:" + resp.getString("msg"));
+				}
+			} else {
+				throw new ServiceException("同步至本系统失败:" + response.getStatusCode());
+			}
+		}
+
+
+		return true;
+	}
+
+	private String login() {
+		try {
+			HttpHeaders headers = new HttpHeaders();
+			headers.setContentType(MediaType.APPLICATION_JSON);
+			JSONObject loginBody = new JSONObject();
+			loginBody.put("username", USERNAME);
+			loginBody.put("password", PASSWORD);
+			HttpEntity<JSONObject> request = new HttpEntity<>(loginBody, headers);
+			ResponseEntity<String> response = restTemplate.exchange(URL_LOGIN, HttpMethod.POST, request, String.class);
+			if (response.getStatusCode().is2xxSuccessful()) {
+				JSONObject resp = JSONObject.parseObject(response.getBody());
+				assert resp != null;
+				Integer code = resp.getInteger("code");
+				if (code == 200) {
+					String token = resp.getString("token");
+					log.info("成功登录工时系统:{}", token);
+					return token;
+				} else {
+					log.error("登录工时系统失败:{}", resp.getString("msg"));
+					throw new ServiceException("登录工时系统失败:" + resp.getString("msg"));
+				}
+			} else {
+				throw new ServiceException("登录工时系统失败:" + response.getStatusCode());
+			}
+		} catch (RestClientException e) {
+			log.error("请求失败: {}", e.getMessage());
+			throw new ServiceException("请求失败:" + e.getMessage());
+		}
+	}
+
+}

+ 1 - 0
kd-service/kd-scientific/src/main/java/org/sky/scientific/service/impl/XmTechnicianHoursServiceImpl.java

@@ -523,4 +523,5 @@ public class XmTechnicianHoursServiceImpl extends BaseServiceImpl<XmTechnicianHo
 			throw new ServiceException("导出失败:" + e.getLocalizedMessage());
 		}
 	}
+
 }