Bladeren bron

钉钉,组织人员导入导出,CCD改为HEVXT

hfy 3 maanden geleden
bovenliggende
commit
defb8faaa7

File diff suppressed because it is too large
+ 1422800 - 0
db/mysql/mes_cloud_liuan.sql


+ 11 - 1
pom.xml

@@ -53,7 +53,18 @@
 			<artifactId>jeesite-module-swagger</artifactId>
 			<version>${project.parent.version}</version>
 		</dependency>
+<!--钉钉消息推送-->
+		<dependency>
+			<groupId>com.aliyun</groupId>
+			<artifactId>alibaba-dingtalk-service-sdk</artifactId>
+			<version>2.0.0</version>
+		</dependency>
 
+		<dependency>
+			<groupId>commons-codec</groupId>
+			<artifactId>commons-codec</artifactId>
+			<version>1.11</version>
+		</dependency>
 		<!-- 内容管理模块 -->
 <!--		<dependency>-->
 <!--			<groupId>com.jeesite</groupId>-->
@@ -88,7 +99,6 @@
 			<artifactId>spring-boot-starter-tomcat</artifactId>
 			<scope>provided</scope>
 		</dependency> -->
-
 		<dependency>
             <groupId>org.elasticsearch.client</groupId>
             <artifactId>elasticsearch-rest-high-level-client</artifactId>

+ 6 - 7
src/main/java/com/jeesite/modules/Application.java

@@ -4,21 +4,19 @@
  */
 package com.jeesite.modules;
 
-import java.net.ServerSocket;
-
 import com.alibaba.fastjson.parser.ParserConfig;
-import com.jeesite.modules.utils.LdNettyServer;
+import com.jeesite.modules.config.BaseConfig;
+import com.jeesite.modules.utils.NettyServer;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
-import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.EnableAsync;
 
-import com.jeesite.modules.config.BaseConfig;
-import com.jeesite.modules.utils.NettyServer;
+import java.net.ServerSocket;
 
 /**
  * Application
@@ -26,6 +24,7 @@ import com.jeesite.modules.utils.NettyServer;
  * @version 2018-10-13
  */
 @SpringBootApplication
+@EnableAsync
 public class Application extends SpringBootServletInitializer implements CommandLineRunner {
 	public static ServerSocket serverSocket = null;
 	@Autowired
@@ -70,4 +69,4 @@ public class Application extends SpringBootServletInitializer implements Command
 	}
 
 
-}
+}

+ 185 - 0
src/main/java/com/jeesite/modules/mes/dingtalk/DingTalkAppClient.java

@@ -0,0 +1,185 @@
+package com.jeesite.modules.mes.dingtalk;
+
+import com.alibaba.fastjson.JSONObject;
+import com.jeesite.common.lang.StringUtils;
+import okhttp3.HttpUrl;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Component
+public class DingTalkAppClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(DingTalkAppClient.class);
+    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+    private static final String TOKEN_URL = "https://oapi.dingtalk.com/gettoken";
+    private static final String USER_BY_MOBILE_URL = "https://oapi.dingtalk.com/topapi/v2/user/getbymobile";
+    private static final String ASYNC_SEND_URL = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2";
+
+    private final DingTalkRobotProperties properties;
+    private final OkHttpClient httpClient = new OkHttpClient.Builder()
+            .connectTimeout(5, TimeUnit.SECONDS)
+            .readTimeout(10, TimeUnit.SECONDS)
+            .build();
+
+    private volatile String accessToken;
+    private volatile long tokenExpireAt;
+
+    public DingTalkAppClient(DingTalkRobotProperties properties) {
+        this.properties = properties;
+    }
+
+    public boolean sendMarkdown(String title, String markdownText) {
+        if (!isConfigured()) {
+            logger.warn("DingTalk app is disabled or app config is incomplete.");
+            return false;
+        }
+        try {
+            String token = getAccessToken();
+            List<String> userIds = getReceiverUserIds(token);
+            List<String> deptIds = split(properties.getDeptIds());
+            if (!properties.isAtAll() && userIds.isEmpty() && deptIds.isEmpty()) {
+                logger.warn("DingTalk app receiver is empty, set ding.user-ids, ding.dept-ids, ding.at-mobiles, or ding.at-all.");
+                return false;
+            }
+
+            JSONObject body = new JSONObject();
+            body.put("agent_id", Long.parseLong(properties.getAgentId().trim()));
+            body.put("to_all_user", properties.isAtAll());
+            if (!userIds.isEmpty()) {
+                body.put("userid_list", String.join(",", userIds));
+            }
+            if (!deptIds.isEmpty()) {
+                body.put("dept_id_list", String.join(",", deptIds));
+            }
+
+            JSONObject markdown = new JSONObject();
+            markdown.put("title", title);
+            markdown.put("text", markdownText);
+            JSONObject msg = new JSONObject();
+            msg.put("msgtype", "markdown");
+            msg.put("markdown", markdown);
+            body.put("msg", msg);
+            return postApi(ASYNC_SEND_URL, token, body, "DingTalk app message send");
+        } catch (Exception ex) {
+            logger.warn("DingTalk app send exception: {}", ex.getMessage(), ex);
+            return false;
+        }
+    }
+
+    private boolean isConfigured() {
+        return properties.isAppEnabled()
+                && StringUtils.isNotBlank(properties.getAgentId())
+                && StringUtils.isNotBlank(properties.getClientId())
+                && StringUtils.isNotBlank(properties.getClientSecret());
+    }
+
+    private String getAccessToken() {
+        long now = System.currentTimeMillis();
+        if (StringUtils.isNotBlank(accessToken) && now < tokenExpireAt) {
+            return accessToken;
+        }
+        synchronized (this) {
+            now = System.currentTimeMillis();
+            if (StringUtils.isNotBlank(accessToken) && now < tokenExpireAt) {
+                return accessToken;
+            }
+            HttpUrl url = HttpUrl.parse(TOKEN_URL).newBuilder()
+                    .addQueryParameter("appkey", properties.getClientId())
+                    .addQueryParameter("appsecret", properties.getClientSecret())
+                    .build();
+            Request request = new Request.Builder().url(url).get().build();
+            try (Response response = httpClient.newCall(request).execute()) {
+                String responseBody = response.body() == null ? "" : response.body().string();
+                if (!response.isSuccessful()) {
+                    throw new IllegalStateException("DingTalk token httpStatus=" + response.code() + ", body=" + responseBody);
+                }
+                JSONObject result = JSONObject.parseObject(responseBody);
+                if (result == null || result.getIntValue("errcode") != 0) {
+                    throw new IllegalStateException("DingTalk token failed: " + responseBody);
+                }
+                accessToken = result.getString("access_token");
+                long expiresIn = result.getLongValue("expires_in");
+                tokenExpireAt = System.currentTimeMillis() + Math.max(60L, expiresIn - 300L) * 1000L;
+                return accessToken;
+            } catch (Exception ex) {
+                accessToken = null;
+                tokenExpireAt = 0;
+                throw new IllegalStateException("Get DingTalk access token failed", ex);
+            }
+        }
+    }
+
+    private List<String> getReceiverUserIds(String token) {
+        List<String> userIds = split(properties.getUserIds());
+        if (!userIds.isEmpty()) {
+            return userIds;
+        }
+        return split(properties.getAtMobiles()).stream()
+                .map(mobile -> getUserIdByMobile(token, mobile))
+                .filter(StringUtils::isNotBlank)
+                .distinct()
+                .collect(Collectors.toList());
+    }
+
+    private String getUserIdByMobile(String token, String mobile) {
+        JSONObject body = new JSONObject();
+        body.put("mobile", mobile);
+        JSONObject result = postApiForResult(USER_BY_MOBILE_URL, token, body, "DingTalk user lookup");
+        if (result == null) {
+            return null;
+        }
+        JSONObject user = result.getJSONObject("result");
+        return user == null ? null : user.getString("userid");
+    }
+
+    private boolean postApi(String apiUrl, String token, JSONObject body, String action) {
+        JSONObject result = postApiForResult(apiUrl, token, body, action);
+        return result != null && result.getIntValue("errcode") == 0;
+    }
+
+    private JSONObject postApiForResult(String apiUrl, String token, JSONObject body, String action) {
+        HttpUrl url = HttpUrl.parse(apiUrl).newBuilder()
+                .addQueryParameter("access_token", token)
+                .build();
+        Request request = new Request.Builder()
+                .url(url)
+                .post(RequestBody.create(JSON, body.toJSONString()))
+                .build();
+        try (Response response = httpClient.newCall(request).execute()) {
+            String responseBody = response.body() == null ? "" : response.body().string();
+            if (!response.isSuccessful()) {
+                logger.warn("{}, httpStatus={}, body={}", action, response.code(), responseBody);
+                return null;
+            }
+            JSONObject result = JSONObject.parseObject(responseBody);
+            if (result == null || result.getIntValue("errcode") != 0) {
+                logger.warn("{} returned failure: {}", action, responseBody);
+            }
+            return result;
+        } catch (Exception ex) {
+            logger.warn("{} exception: {}", action, ex.getMessage(), ex);
+            return null;
+        }
+    }
+
+    private List<String> split(String value) {
+        if (StringUtils.isBlank(value)) {
+            return java.util.Collections.emptyList();
+        }
+        return Stream.of(value.split(","))
+                .map(String::trim)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toList());
+    }
+}

+ 133 - 0
src/main/java/com/jeesite/modules/mes/dingtalk/DingTalkRobotClient.java

@@ -0,0 +1,133 @@
+package com.jeesite.modules.mes.dingtalk;
+
+import com.alibaba.fastjson.JSONObject;
+import com.jeesite.common.lang.StringUtils;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Component
+public class DingTalkRobotClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(DingTalkRobotClient.class);
+    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
+
+    private final DingTalkRobotProperties properties;
+    private final OkHttpClient httpClient = new OkHttpClient.Builder()
+            .connectTimeout(5, TimeUnit.SECONDS)
+            .readTimeout(10, TimeUnit.SECONDS)
+            .build();
+
+    public DingTalkRobotClient(DingTalkRobotProperties properties) {
+        this.properties = properties;
+    }
+
+    public boolean sendMarkdown(String title, String markdownText) {
+        if (!properties.isEnabled() || StringUtils.isBlank(properties.getUrl())) {
+            logger.warn("DingTalk robot is disabled or webhook url is empty.");
+            return false;
+        }
+        JSONObject body = new JSONObject();
+        body.put("msgtype", "markdown");
+        JSONObject markdown = new JSONObject();
+        markdown.put("title", title);
+        markdown.put("text", appendAtText(markdownText));
+        body.put("markdown", markdown);
+        body.put("at", buildAt());
+        return post(body);
+    }
+
+    private JSONObject buildAt() {
+        JSONObject at = new JSONObject();
+        at.put("isAtAll", properties.isAtAll());
+        List<String> mobiles = getAtMobiles();
+        if (!mobiles.isEmpty()) {
+            at.put("atMobiles", mobiles);
+        }
+        return at;
+    }
+
+    private String appendAtText(String markdownText) {
+        List<String> mobiles = getAtMobiles();
+        if (mobiles.isEmpty()) {
+            return markdownText;
+        }
+        String atText = mobiles.stream()
+                .map(mobile -> "@" + mobile)
+                .collect(Collectors.joining(" "));
+        return markdownText + "\n\n" + atText;
+    }
+
+    private List<String> getAtMobiles() {
+        if (StringUtils.isBlank(properties.getAtMobiles())) {
+            return java.util.Collections.emptyList();
+        }
+        return Stream.of(properties.getAtMobiles().split(","))
+                .map(String::trim)
+                .filter(StringUtils::isNotBlank)
+                .collect(Collectors.toList());
+    }
+
+    private boolean post(JSONObject body) {
+        String requestUrl = buildSignedUrl();
+        Request request = new Request.Builder()
+                .url(requestUrl)
+                .post(RequestBody.create(JSON, body.toJSONString()))
+                .build();
+        try (Response response = httpClient.newCall(request).execute()) {
+            String responseBody = response.body() == null ? "" : response.body().string();
+            if (!response.isSuccessful()) {
+                logger.warn("DingTalk robot send failed, httpStatus={}, body={}", response.code(), responseBody);
+                return false;
+            }
+            JSONObject result = JSONObject.parseObject(responseBody);
+            boolean success = result != null && result.getIntValue("errcode") == 0;
+            if (!success) {
+                logger.warn("DingTalk robot returned failure: {}", responseBody);
+            }
+            return success;
+        } catch (Exception ex) {
+            logger.warn("DingTalk robot send exception: {}", ex.getMessage(), ex);
+            return false;
+        }
+    }
+
+    private String buildSignedUrl() {
+        String url = properties.getUrl();
+        if (StringUtils.isBlank(properties.getSecret())) {
+            return url;
+        }
+        long timestamp = System.currentTimeMillis();
+        String sign = sign(timestamp, properties.getSecret());
+        String separator = url.contains("?") ? "&" : "?";
+        return url + separator + "timestamp=" + timestamp + "&sign=" + sign;
+    }
+
+    private String sign(long timestamp, String secret) {
+        try {
+            String stringToSign = timestamp + "\n" + secret;
+            Mac mac = Mac.getInstance("HmacSHA256");
+            mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
+            byte[] signData = mac.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8));
+            String base64 = Base64.getEncoder().encodeToString(signData);
+            return URLEncoder.encode(base64, StandardCharsets.UTF_8.name());
+        } catch (Exception ex) {
+            throw new IllegalStateException("Build DingTalk sign failed", ex);
+        }
+    }
+}

+ 109 - 0
src/main/java/com/jeesite/modules/mes/dingtalk/DingTalkRobotProperties.java

@@ -0,0 +1,109 @@
+package com.jeesite.modules.mes.dingtalk;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "ding")
+public class DingTalkRobotProperties {
+
+    private boolean enabled = true;
+    private String url;
+    private String secret;
+    private String atMobiles;
+    private boolean atAll;
+    private boolean appEnabled = false;
+    private String agentId;
+    private String clientId;
+    private String clientSecret;
+    private String userIds;
+    private String deptIds;
+
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getSecret() {
+        return secret;
+    }
+
+    public void setSecret(String secret) {
+        this.secret = secret;
+    }
+
+    public String getAtMobiles() {
+        return atMobiles;
+    }
+
+    public void setAtMobiles(String atMobiles) {
+        this.atMobiles = atMobiles;
+    }
+
+    public boolean isAtAll() {
+        return atAll;
+    }
+
+    public void setAtAll(boolean atAll) {
+        this.atAll = atAll;
+    }
+
+    public boolean isAppEnabled() {
+        return appEnabled;
+    }
+
+    public void setAppEnabled(boolean appEnabled) {
+        this.appEnabled = appEnabled;
+    }
+
+    public String getAgentId() {
+        return agentId;
+    }
+
+    public void setAgentId(String agentId) {
+        this.agentId = agentId;
+    }
+
+    public String getClientId() {
+        return clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public String getUserIds() {
+        return userIds;
+    }
+
+    public void setUserIds(String userIds) {
+        this.userIds = userIds;
+    }
+
+    public String getDeptIds() {
+        return deptIds;
+    }
+
+    public void setDeptIds(String deptIds) {
+        this.deptIds = deptIds;
+    }
+}

+ 135 - 0
src/main/java/com/jeesite/modules/mes/dingtalk/MesDingTalkAlertService.java

@@ -0,0 +1,135 @@
+package com.jeesite.modules.mes.dingtalk;
+
+import com.jeesite.common.lang.DateUtils;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.modules.mes.entity.*;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+
+@Service
+public class MesDingTalkAlertService {
+
+    private final DingTalkRobotClient robotClient;
+    private final DingTalkAppClient appClient;
+
+    public MesDingTalkAlertService(DingTalkRobotClient robotClient, DingTalkAppClient appClient) {
+        this.robotClient = robotClient;
+        this.appClient = appClient;
+    }
+
+    @Async
+    public void sendProductionAlarm(MesProcessAlarm alarm) {
+        sendMarkdown("生产异常预警", buildMessage("生产异常预警",
+                field("产线", alarm.getLineSn()),
+                field("工位", alarm.getOprno()),
+                field("工件码", alarm.getSn()),
+                field("备注", alarm.getRemark()),
+                field("状态", alarm.getState()),
+                field("记录ID", alarm.getId())));
+    }
+    @Async
+    public void sendProductionQuality(MesQuality alarm) {
+        sendMarkdown("抽检预警", buildMessage("抽检预警",
+                field("产线", alarm.getLineSn()),
+                field("工位", alarm.getOprno()),
+                field("工件码", alarm.getSn()),
+                field("备注", alarm.getRemark()),
+                field("结果", alarm.getResult()),
+                field("记录ID", alarm.getId())));
+    }
+    @Async
+    public void sendDeviceAlarm(MesDeviceAlarm alarm) {
+        sendMarkdown("设备异常预警", buildMessage("设备异常预警",
+                field("设备编号", alarm.getDeviceSn()),
+                field("报警类型", alarm.getType()),
+                field("报警参数", alarm.getContent()),
+                field("备注", alarm.getRemark()),
+                field("状态", alarm.getState()),
+                field("记录ID", alarm.getId())));
+    }
+
+    @Async
+    public void sendQualityAlarm(MesProductQuality quality) {
+        if (isOk(quality.getResult())) {
+            return;
+        }
+        sendMarkdown("品质异常预警", buildMessage("品质异常预警",
+                field("工件码", quality.getSn()),
+                field("工位", quality.getOprno()),
+                field("工件类型", quality.getCateSn()),
+                field("结果", quality.getResult()),
+                field("记录ID", quality.getId())));
+    }
+
+    @Async
+    public void sendQmAlarm(MesProductQm qm) {
+        if (isOk(qm.getTestResult())) {
+            return;
+        }
+        sendMarkdown("品质异常预警", buildMessage("气密检测异常预警",
+                field("工件号", qm.getComponentNum()),
+                field("产线", qm.getLineSn()),
+                field("工位", qm.getOprno()),
+                field("设备类型", qm.getDeviceType()),
+                field("测试结果", qm.getTestResult()),
+                field("泄漏值", join(qm.getLeakVal(), qm.getLeakValUnit())),
+                field("泄漏率", join(qm.getLeakRate(), qm.getLeakRateUnit())),
+                field("记录ID", qm.getId())));
+    }
+
+    @Async
+    public void sendMaterialBadAlarm(MesMaterialBlpRecord record) {
+        sendMarkdown("物料异常预警", buildMessage("来料不良预警",
+                field("物料名称", record.getTitle()),
+                field("数量", record.getNums()),
+                field("发货日期", record.getFaDate()),
+                field("状态", record.getState()),
+                field("检查记录ID", record.getCheckRecordId()),
+                field("记录ID", record.getId())));
+    }
+
+    @Async
+    public void sendMaterialScrapAlarm(MesMaterialBfRecord record) {
+        sendMarkdown("物料异常预警", buildMessage("来料报废预警",
+                field("状态", record.getState()),
+                field("备注", record.getRemark()),
+                field("记录ID", record.getId())));
+    }
+
+    private void sendMarkdown(String title, String markdownText) {
+        robotClient.sendMarkdown(title, markdownText);
+        appClient.sendMarkdown(title, markdownText);
+    }
+
+    private String buildMessage(String title, String... fields) {
+        StringBuilder text = new StringBuilder();
+        text.append("### ").append(title).append("\n\n");
+        text.append("- 预警时间:").append(DateUtils.formatDateTime(new Date())).append("\n");
+        for (String field : fields) {
+            if (StringUtils.isNotBlank(field)) {
+                text.append(field);
+            }
+        }
+        return text.toString();
+    }
+
+    private String field(String name, String value) {
+        if (StringUtils.isBlank(value)) {
+            return "";
+        }
+        return "- " + name + ":" + value + "\n";
+    }
+
+    private String join(String value, String unit) {
+        if (StringUtils.isBlank(value)) {
+            return "";
+        }
+        return value + StringUtils.defaultString(unit);
+    }
+
+    private boolean isOk(String result) {
+        return StringUtils.isNotBlank(result) && "OK".equalsIgnoreCase(result.trim());
+    }
+}

+ 15 - 18
src/main/java/com/jeesite/modules/mes/service/MesProductCcdService.java

@@ -1,31 +1,28 @@
 package com.jeesite.modules.mes.service;
 
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
-import java.util.List;
-
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
 import com.jeesite.common.lang.StringUtils;
-import com.jeesite.modules.mes.entity.MesProduct;
-import com.jeesite.modules.mes.entity.MesProductRecord;
+import com.jeesite.common.service.CrudService;
+import com.jeesite.common.service.ServiceException;
+import com.jeesite.common.utils.excel.ExcelImport;
+import com.jeesite.common.validator.ValidatorUtils;
+import com.jeesite.modules.mes.dao.MesProductCcdDao;
+import com.jeesite.modules.mes.entity.MesProductCcd;
 import com.jeesite.modules.mes.resp.BindMaterialResp;
 import com.jeesite.modules.mes.resp.ParamsResp;
 import com.jeesite.modules.mes.util.CommonUitl;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
-
-import com.jeesite.common.entity.Page;
-import com.jeesite.common.service.CrudService;
-import com.jeesite.modules.mes.entity.MesProductCcd;
-import com.jeesite.modules.mes.dao.MesProductCcdDao;
-import com.jeesite.common.service.ServiceException;
-import com.jeesite.common.config.Global;
-import com.jeesite.common.validator.ValidatorUtils;
-import com.jeesite.common.utils.excel.ExcelImport;
 import org.springframework.web.multipart.MultipartFile;
+
 import javax.validation.ConstraintViolation;
 import javax.validation.ConstraintViolationException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * 视觉检测记录Service
@@ -185,7 +182,7 @@ public class MesProductCcdService extends CrudService<MesProductCcdDao, MesProdu
 
 		String sn = parts[2];	//序号
 		String oprno = parts[3]; // OP290B
-		String lineSn = "XT";	//产线编号
+		String lineSn = "HEVXT";	//产线编号
 		String title = parts[4];//设备名称
 		oprno = CommonUitl.formatOprno(oprno);
 		if(StringUtils.isEmpty(sn)){
@@ -251,7 +248,7 @@ public class MesProductCcdService extends CrudService<MesProductCcdDao, MesProdu
 
 		String sn = parts[2];
 		String oprno = parts[3];
-		String lineSn = "XT";
+		String lineSn = "HEVXT";
 		String result = parts[7];
 		String userCode = parts[1];
 		String craft = "100000";

+ 1 - 1
src/main/java/com/jeesite/modules/mes/web/MesProductRecordController.java

@@ -3970,7 +3970,7 @@ public class MesProductRecordController extends BaseController {
 				}
 				String sn = commands[2];
 				String oprno = commands[3]; // OP290B
-				String lineSn = "XT";
+				String lineSn = "HEVXT";
 				String oldOprno = oprno;
 				oprno = CommonUitl.formatOprno(oprno);
 				if (StringUtils.isEmpty(sn)) {

+ 7 - 1
src/main/java/com/jeesite/modules/mes/web/MesQualityController.java

@@ -12,6 +12,7 @@ import com.jeesite.common.utils.excel.ExcelExport;
 import com.jeesite.common.web.BaseController;
 import com.jeesite.modules.file.entity.FileUpload;
 import com.jeesite.modules.file.service.FileUploadService;
+import com.jeesite.modules.mes.dingtalk.MesDingTalkAlertService;
 import com.jeesite.modules.mes.entity.*;
 import com.jeesite.modules.mes.resp.CommonResp;
 import com.jeesite.modules.mes.service.*;
@@ -65,6 +66,8 @@ public class MesQualityController extends BaseController {
 
 	@Resource
 	private FileUploadService fileUploadService;
+	@Autowired
+	private MesDingTalkAlertService mesDingTalkAlertService;
 
 	/**
 	 * 获取数据
@@ -109,11 +112,14 @@ public class MesQualityController extends BaseController {
 	/**
 	 * 保存数据
 	 */
-	@RequiresPermissions("mes:mesQuality:edit")
 	@PostMapping(value = "save")
 	@ResponseBody
 	public String save(@Validated MesQuality mesQuality) {
+		boolean isNewRecord = mesQuality.getIsNewRecord();
 		mesQualityService.save(mesQuality);
+		if (isNewRecord) {
+			mesDingTalkAlertService.sendProductionQuality(mesQuality);
+		}
 		return renderResult(Global.TRUE, text("保存抽检记录成功!"));
 	}
 

+ 15 - 0
src/main/resources/config/application.yml

@@ -18,6 +18,20 @@ apiMode: false
 
 tess4j:
   datapath: D:/tessdata
+#钉钉消息推送
+ding:
+  secret: SECb120c104d1b5fdfac620e4242e6c92ea235b5bca60f80fb80b5551675586bd8c
+  url: https://oapi.dingtalk.com/robot/send?access_token=2a0bfcade1c1725dd9634474aca9c360fa67b1922d0a13495bd23a50f2bdb561
+  at-mobiles: 19120501982
+  at-all: false
+  app-enabled: true
+  app-id: 2372e61f-33b9-436c-b174-f58aa3049759
+  agent-id: 4724073992
+  client-id: dingpr9lhefdgk79mhqx
+  client-secret: 18ClEucl6Fg2w_HwUGtqSgTiSmA1S_7Qee9GLp63xlVQPAQKWwB93A0QcEBidKOQ
+  user-ids:
+  dept-ids:
+
 
 # ADW300-WiFi MQTT接收配置。先保持store.enabled=false,确认能收到报文后再建表并打开入库。
 adw300:
@@ -708,6 +722,7 @@ shiro:
   filterChainDefinitions: |
     ${adminPath}/mes/mesApp/ver = anon
     ${adminPath}/mes/mesLogin/login = anon
+    ${adminPath}/mes/mesQuality/save = anon
     ${adminPath}/sys/emailLogin/sendCode = anon
     ${adminPath}/sys/emailLogin/login = anon
     ${adminPath}/sys/emailLogin/verify = anon