添加数据贯通代码未调试
This commit is contained in:
@@ -0,0 +1,411 @@
|
|||||||
|
package com.klp.framework.client;
|
||||||
|
|
||||||
|
import com.klp.framework.config.SqlServerApiProperties;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql-server-api 统一调用客户端。
|
||||||
|
* <p>
|
||||||
|
* 对齐 {@code sql-server-api/app.py} 的接口规范:
|
||||||
|
* <ul>
|
||||||
|
* <li>GET /health</li>
|
||||||
|
* <li>GET /heartbeat</li>
|
||||||
|
* <li>POST /table-schema</li>
|
||||||
|
* <li>POST /execute-sql</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SqlServerApiClient {
|
||||||
|
|
||||||
|
private final RestTemplate restTemplate;
|
||||||
|
private final SqlServerApiProperties properties;
|
||||||
|
|
||||||
|
public SqlServerApiClient(RestTemplate sqlServerApiRestTemplate, SqlServerApiProperties properties) {
|
||||||
|
this.restTemplate = sqlServerApiRestTemplate;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseUrl() {
|
||||||
|
return normalizeBaseUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> health() {
|
||||||
|
return getForMap("/health");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> heartbeat() {
|
||||||
|
return getForMap("/heartbeat");
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableSchemaResponse tableSchema(String tableType, String tableName) {
|
||||||
|
return postForObject("/table-schema", new TableSchemaRequest(tableType, tableName), TableSchemaResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse executeSql(String tableType, String sql, Map<String, Object> params) {
|
||||||
|
return postForObject("/execute-sql", new ExecuteSqlRequest(tableType, sql, params), ExecuteSqlResponse.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T get(String path, Class<T> responseType) {
|
||||||
|
return restTemplate.getForObject(buildUri(path), responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T get(String path, Map<String, ?> queryParams, Class<T> responseType) {
|
||||||
|
URI uri = UriComponentsBuilder.fromHttpUrl(normalizeBaseUrl())
|
||||||
|
.path(normalizePath(path))
|
||||||
|
.queryParams(convertToQueryParams(queryParams))
|
||||||
|
.build(true)
|
||||||
|
.toUri();
|
||||||
|
return restTemplate.getForObject(uri, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T, R> T post(String path, R requestBody, Class<T> responseType) {
|
||||||
|
return restTemplate.postForObject(buildUri(path), requestBody, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TableSchemaRequest {
|
||||||
|
private String tableType;
|
||||||
|
private String tableName;
|
||||||
|
|
||||||
|
public TableSchemaRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public TableSchemaRequest(String tableType, String tableName) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
this.tableName = tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableType() {
|
||||||
|
return tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableType(String tableType) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableName() {
|
||||||
|
return tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableName(String tableName) {
|
||||||
|
this.tableName = tableName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExecuteSqlRequest {
|
||||||
|
private String tableType;
|
||||||
|
private String sql;
|
||||||
|
private Map<String, Object> params;
|
||||||
|
|
||||||
|
public ExecuteSqlRequest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlRequest(String tableType, String sql, Map<String, Object> params) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
this.sql = sql;
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableType() {
|
||||||
|
return tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableType(String tableType) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSql() {
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSql(String sql) {
|
||||||
|
this.sql = sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getParams() {
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParams(Map<String, Object> params) {
|
||||||
|
this.params = params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TableSchemaResponse {
|
||||||
|
private String tableType;
|
||||||
|
private String tableName;
|
||||||
|
private Schema schema;
|
||||||
|
|
||||||
|
public String getTableType() {
|
||||||
|
return tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableType(String tableType) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTableName() {
|
||||||
|
return tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableName(String tableName) {
|
||||||
|
this.tableName = tableName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Schema getSchema() {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSchema(Schema schema) {
|
||||||
|
this.schema = schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Schema {
|
||||||
|
private List<Column> columns = Collections.emptyList();
|
||||||
|
|
||||||
|
public List<Column> getColumns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setColumns(List<Column> columns) {
|
||||||
|
this.columns = columns;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Column {
|
||||||
|
private String name;
|
||||||
|
private String type;
|
||||||
|
private boolean nullable;
|
||||||
|
private Object defaultValue;
|
||||||
|
private boolean primaryKey;
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isNullable() {
|
||||||
|
return nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNullable(boolean nullable) {
|
||||||
|
this.nullable = nullable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getDefaultValue() {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDefaultValue(Object defaultValue) {
|
||||||
|
this.defaultValue = defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrimaryKey() {
|
||||||
|
return primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPrimaryKey(boolean primaryKey) {
|
||||||
|
this.primaryKey = primaryKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ExecuteSqlResponse {
|
||||||
|
private String tableType;
|
||||||
|
private String resultType;
|
||||||
|
private Integer rowCount;
|
||||||
|
private Object result;
|
||||||
|
|
||||||
|
public String getTableType() {
|
||||||
|
return tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTableType(String tableType) {
|
||||||
|
this.tableType = tableType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResultType() {
|
||||||
|
return resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResultType(String resultType) {
|
||||||
|
this.resultType = resultType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getRowCount() {
|
||||||
|
return rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRowCount(Integer rowCount) {
|
||||||
|
this.rowCount = rowCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(Object result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getForMap(String path) {
|
||||||
|
ResponseEntity<Map> responseEntity = restTemplate.exchange(buildUri(path), HttpMethod.GET, HttpEntity.EMPTY, Map.class);
|
||||||
|
Map<String, Object> body = responseEntity.getBody();
|
||||||
|
return body == null ? Collections.emptyMap() : body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> T postForObject(String path, Object requestBody, Class<T> responseType) {
|
||||||
|
return restTemplate.postForObject(buildUri(path), requestBody, responseType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private URI buildUri(String path) {
|
||||||
|
return UriComponentsBuilder.fromHttpUrl(normalizeBaseUrl())
|
||||||
|
.path(normalizePath(path))
|
||||||
|
.build(true)
|
||||||
|
.toUri();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeBaseUrl() {
|
||||||
|
if (properties.getBaseUrl() != null && properties.getBaseUrl().trim().length() > 0) {
|
||||||
|
return properties.getBaseUrl();
|
||||||
|
}
|
||||||
|
if (properties.getHost() == null || properties.getHost().trim().length() == 0 || properties.getPort() == null) {
|
||||||
|
throw new IllegalStateException("sql-server-api 配置缺失,请检查 host/port/base-url");
|
||||||
|
}
|
||||||
|
return "http://" + properties.getHost() + ":" + properties.getPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizePath(String path) {
|
||||||
|
if (path == null || path.trim().length() == 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return path.startsWith("/") ? path : "/" + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryPlanByCoilId(String coilId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PDI_PLAN where COILID = :coilId",
|
||||||
|
singletonParam("coilId", coilId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryPlanList() {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PDI_PLAN order by INSDATE desc",
|
||||||
|
emptyParams()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryPlanListByProcessCode(String processCode) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PDI_PLAN where PROCESS_CODE = :processCode order by INSDATE desc",
|
||||||
|
singletonParam("processCode", processCode)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryPlanListByStatus(String status) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PDI_PLAN where STATUS = :status order by INSDATE desc",
|
||||||
|
singletonParam("status", status)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryPlanByHotCoilId(String hotCoilId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PDI_PLAN where HOT_COILID = :hotCoilId",
|
||||||
|
singletonParam("hotCoilId", hotCoilId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryProSegByEncoilId(String encoilId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PRO_SEG where ENCOILID = :encoilId order by SEGNO",
|
||||||
|
singletonParam("encoilId", encoilId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryProSegByExcoilId(String excoilId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.PLTCM_PRO_SEG where EXCOILID = :excoilId order by SEGNO",
|
||||||
|
singletonParam("excoilId", excoilId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryQualityByExcoilId(String excoilId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.V_PLTCM_PDO_QUALITY where EXCOILID = :excoilId order by END_DATE desc",
|
||||||
|
singletonParam("excoilId", excoilId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryGaugeByMatId(String matId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.V_VBDA_GAUGE where MATID = :matId order by XTIME asc",
|
||||||
|
singletonParam("matId", matId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecuteSqlResponse queryShapeByMatId(String matId) {
|
||||||
|
return executeSql(
|
||||||
|
"oracle",
|
||||||
|
"select * from JXPLTCM.V_VBDA_SHAPE where MATID = :matId order by XTIME asc",
|
||||||
|
singletonParam("matId", matId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private org.springframework.util.MultiValueMap<String, String> convertToQueryParams(Map<String, ?> queryParams) {
|
||||||
|
org.springframework.util.LinkedMultiValueMap<String, String> multiValueMap = new org.springframework.util.LinkedMultiValueMap<>();
|
||||||
|
if (queryParams == null || queryParams.isEmpty()) {
|
||||||
|
return multiValueMap;
|
||||||
|
}
|
||||||
|
for (Map.Entry<String, ?> entry : queryParams.entrySet()) {
|
||||||
|
Object value = entry.getValue();
|
||||||
|
if (value != null) {
|
||||||
|
multiValueMap.add(entry.getKey(), String.valueOf(value));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return multiValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> singletonParam(String key, Object value) {
|
||||||
|
java.util.HashMap<String, Object> params = new java.util.HashMap<String, Object>();
|
||||||
|
if (value != null) {
|
||||||
|
params.put(key, value);
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> emptyParams() {
|
||||||
|
return new java.util.HashMap<String, Object>();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.klp.framework.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql-server-api HTTP 客户端配置
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SqlServerApiClientConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RestTemplate sqlServerApiRestTemplate(RestTemplateBuilder builder) {
|
||||||
|
return builder
|
||||||
|
.setConnectTimeout(Duration.ofSeconds(5))
|
||||||
|
.setReadTimeout(Duration.ofSeconds(30))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.klp.framework.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql-server-api 中间件配置
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@ConfigurationProperties(prefix = "sql-server-api")
|
||||||
|
public class SqlServerApiProperties {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求地址
|
||||||
|
*/
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 请求端口
|
||||||
|
*/
|
||||||
|
private Integer port;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基础访问地址
|
||||||
|
*/
|
||||||
|
private String baseUrl;
|
||||||
|
|
||||||
|
public String getHost() {
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHost(String host) {
|
||||||
|
this.host = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getPort() {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPort(Integer port) {
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseUrl() {
|
||||||
|
return baseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBaseUrl(String baseUrl) {
|
||||||
|
this.baseUrl = baseUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
package com.klp.framework.service;
|
||||||
|
|
||||||
|
import com.klp.framework.client.SqlServerApiClient;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 面向业务场景的 sql-server-api 查询服务。
|
||||||
|
* <p>
|
||||||
|
* 当前抽象为三个功能:
|
||||||
|
* <ol>
|
||||||
|
* <li>计划查询</li>
|
||||||
|
* <li>钢卷实际 / SEG 查询</li>
|
||||||
|
* <li>实时数据(Gauge / Shape)查询</li>
|
||||||
|
* </ol>
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class SqlServerApiBusinessService {
|
||||||
|
|
||||||
|
private final SqlServerApiClient client;
|
||||||
|
|
||||||
|
public SqlServerApiBusinessService(SqlServerApiClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划列表:查询所有计划,按时间倒序。
|
||||||
|
* <p>
|
||||||
|
* 这是后续按 coilId 关联 SEG、实时数据的入口。
|
||||||
|
*/
|
||||||
|
public PlanListView getPlanList() {
|
||||||
|
return PlanListView.fromExecuteSqlResponse(client.queryPlanList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划列表:按工艺流程编码筛选。
|
||||||
|
*/
|
||||||
|
public PlanListView getPlanListByProcessCode(String processCode) {
|
||||||
|
return PlanListView.fromExecuteSqlResponse(client.queryPlanListByProcessCode(processCode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划列表:按状态筛选。
|
||||||
|
*/
|
||||||
|
public PlanListView getPlanListByStatus(String status) {
|
||||||
|
return PlanListView.fromExecuteSqlResponse(client.queryPlanListByStatus(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划详情:按成品卷号查询单条计划。
|
||||||
|
*/
|
||||||
|
public PlanDetailView getPlanByCoilId(String coilId) {
|
||||||
|
return PlanDetailView.fromExecuteSqlResponse(coilId, client.queryPlanByCoilId(coilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划详情:按热卷号查询。
|
||||||
|
*/
|
||||||
|
public PlanDetailView getPlanByHotCoilId(String hotCoilId) {
|
||||||
|
return PlanDetailView.fromExecuteSqlResponse(hotCoilId, client.queryPlanByHotCoilId(hotCoilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钢卷实际 SEG 查询:按入口卷号查询。
|
||||||
|
* <p>
|
||||||
|
* 返回的是按 SEGNO 排序后的原始行数据。
|
||||||
|
*/
|
||||||
|
public SegSeriesView getSegByEncoilId(String encoilId) {
|
||||||
|
return SegSeriesView.fromExecuteSqlResponse(encoilId, client.queryProSegByEncoilId(encoilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钢卷实际 SEG 查询:按出口卷号查询。
|
||||||
|
*/
|
||||||
|
public SegSeriesView getSegByExcoilId(String excoilId) {
|
||||||
|
return SegSeriesView.fromExecuteSqlResponse(excoilId, client.queryProSegByExcoilId(excoilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钢卷 SEG 视图数据:把同一钢卷下按 SEGNO 排序的多行数据,整理成“一个钢卷 id + 一个属性对应一个列表”的结构。
|
||||||
|
* <p>
|
||||||
|
* 例如:厚度、张力、速度都会被整理成数组,方便前端直接画表或曲线。
|
||||||
|
*/
|
||||||
|
public SegSeriesView getSegSeriesViewByEncoilId(String encoilId) {
|
||||||
|
return getSegByEncoilId(encoilId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时数据:厚度/仪表数据。
|
||||||
|
*/
|
||||||
|
public SqlServerApiClient.ExecuteSqlResponse getRealtimeGaugeByMatId(String matId) {
|
||||||
|
return client.queryGaugeByMatId(matId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时数据:板形/形状数据。
|
||||||
|
*/
|
||||||
|
public SqlServerApiClient.ExecuteSqlResponse getRealtimeShapeByMatId(String matId) {
|
||||||
|
return client.queryShapeByMatId(matId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时数据总入口:一次性返回厚度与板形两类数据。
|
||||||
|
*/
|
||||||
|
public RealtimeDataBundle getRealtimeData(String matId) {
|
||||||
|
return new RealtimeDataBundle(
|
||||||
|
getRealtimeGaugeByMatId(matId),
|
||||||
|
getRealtimeShapeByMatId(matId)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PlanListView toPlanListView(SqlServerApiClient.ExecuteSqlResponse response) {
|
||||||
|
return PlanListView.fromExecuteSqlResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Map<String, Object>> asRowList(SqlServerApiClient.ExecuteSqlResponse response) {
|
||||||
|
if (response == null || response.getResult() == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
Object result = response.getResult();
|
||||||
|
if (result instanceof List) {
|
||||||
|
List<?> list = (List<?>) result;
|
||||||
|
List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
|
||||||
|
for (Object item : list) {
|
||||||
|
if (item instanceof Map) {
|
||||||
|
rows.add((Map<String, Object>) item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Number asNumber(Object value) {
|
||||||
|
if (value instanceof Number) {
|
||||||
|
return (Number) value;
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new BigDecimal(String.valueOf(value));
|
||||||
|
} catch (Exception ex) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String asString(Object value) {
|
||||||
|
return value == null ? null : String.valueOf(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlanListView {
|
||||||
|
private final List<String> coilIds;
|
||||||
|
private final List<Map<String, Object>> rows;
|
||||||
|
|
||||||
|
public PlanListView(List<String> coilIds, List<Map<String, Object>> rows) {
|
||||||
|
this.coilIds = coilIds;
|
||||||
|
this.rows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getCoilIds() {
|
||||||
|
return coilIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, Object>> getRows() {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlanListView fromExecuteSqlResponse(SqlServerApiClient.ExecuteSqlResponse response) {
|
||||||
|
List<Map<String, Object>> rows = asRowList(response);
|
||||||
|
List<String> coilIds = rows.stream()
|
||||||
|
.map(row -> asString(row.get("COILID")))
|
||||||
|
.filter(value -> value != null && value.trim().length() > 0)
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
return new PlanListView(coilIds, rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PlanDetailView {
|
||||||
|
private final String coilId;
|
||||||
|
private final List<Map<String, Object>> rows;
|
||||||
|
private final Map<String, Object> firstRow;
|
||||||
|
|
||||||
|
public PlanDetailView(String coilId, List<Map<String, Object>> rows, Map<String, Object> firstRow) {
|
||||||
|
this.coilId = coilId;
|
||||||
|
this.rows = rows;
|
||||||
|
this.firstRow = firstRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCoilId() {
|
||||||
|
return coilId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, Object>> getRows() {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getFirstRow() {
|
||||||
|
return firstRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PlanDetailView fromExecuteSqlResponse(String coilId, SqlServerApiClient.ExecuteSqlResponse response) {
|
||||||
|
List<Map<String, Object>> rows = asRowList(response);
|
||||||
|
Map<String, Object> firstRow = rows.isEmpty() ? Collections.<String, Object>emptyMap() : rows.get(0);
|
||||||
|
return new PlanDetailView(coilId, rows, firstRow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class SegSeriesView {
|
||||||
|
private final String coilId;
|
||||||
|
private final List<Integer> segNo;
|
||||||
|
private final Map<String, List<Object>> series;
|
||||||
|
private final List<Map<String, Object>> rows;
|
||||||
|
|
||||||
|
public SegSeriesView(String coilId, List<Integer> segNo, Map<String, List<Object>> series, List<Map<String, Object>> rows) {
|
||||||
|
this.coilId = coilId;
|
||||||
|
this.segNo = segNo;
|
||||||
|
this.series = series;
|
||||||
|
this.rows = rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCoilId() {
|
||||||
|
return coilId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getSegNo() {
|
||||||
|
return segNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<Object>> getSeries() {
|
||||||
|
return series;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Map<String, Object>> getRows() {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static SegSeriesView fromExecuteSqlResponse(String coilId, SqlServerApiClient.ExecuteSqlResponse response) {
|
||||||
|
List<Map<String, Object>> rows = asRowList(response);
|
||||||
|
Collections.sort(rows, new Comparator<Map<String, Object>>() {
|
||||||
|
@Override
|
||||||
|
public int compare(Map<String, Object> left, Map<String, Object> right) {
|
||||||
|
Number leftSeg = asNumber(left.get("SEGNO"));
|
||||||
|
Number rightSeg = asNumber(right.get("SEGNO"));
|
||||||
|
int leftValue = leftSeg == null ? Integer.MAX_VALUE : leftSeg.intValue();
|
||||||
|
int rightValue = rightSeg == null ? Integer.MAX_VALUE : rightSeg.intValue();
|
||||||
|
if (leftValue > rightValue) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (leftValue < rightValue) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
List<Integer> segNo = new ArrayList<Integer>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Number seg = asNumber(row.get("SEGNO"));
|
||||||
|
segNo.add(seg == null ? null : seg.intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<Object>> series = new LinkedHashMap<String, List<Object>>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
for (Map.Entry<String, Object> entry : row.entrySet()) {
|
||||||
|
String key = entry.getKey();
|
||||||
|
if ("SEGNO".equalsIgnoreCase(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
series.computeIfAbsent(key, ignored -> new ArrayList<>()).add(entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SegSeriesView(coilId, segNo, series, rows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class RealtimeDataBundle {
|
||||||
|
private final SqlServerApiClient.ExecuteSqlResponse gauge;
|
||||||
|
private final SqlServerApiClient.ExecuteSqlResponse shape;
|
||||||
|
|
||||||
|
public RealtimeDataBundle(SqlServerApiClient.ExecuteSqlResponse gauge,
|
||||||
|
SqlServerApiClient.ExecuteSqlResponse shape) {
|
||||||
|
this.gauge = gauge;
|
||||||
|
this.shape = shape;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SqlServerApiClient.ExecuteSqlResponse getGauge() {
|
||||||
|
return gauge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SqlServerApiClient.ExecuteSqlResponse getShape() {
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package com.klp.web.controller.sqlserver;
|
||||||
|
|
||||||
|
import com.klp.common.core.domain.R;
|
||||||
|
import com.klp.framework.service.SqlServerApiBusinessService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sql-server-api 业务查询接口。
|
||||||
|
* <p>
|
||||||
|
* 提供计划、SEG、实时数据三个入口,方便前端联动展示。
|
||||||
|
*/
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/sql-server-api")
|
||||||
|
public class SqlServerApiController {
|
||||||
|
|
||||||
|
private final SqlServerApiBusinessService businessService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划列表。
|
||||||
|
*/
|
||||||
|
@GetMapping("/plans")
|
||||||
|
public R<SqlServerApiBusinessService.PlanListView> planList() {
|
||||||
|
return R.ok(businessService.getPlanList());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划详情。
|
||||||
|
*/
|
||||||
|
@GetMapping("/plans/{coilId}")
|
||||||
|
public R<SqlServerApiBusinessService.PlanDetailView> planDetail(@PathVariable String coilId) {
|
||||||
|
return R.ok(businessService.getPlanByCoilId(coilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钢卷实际 SEG,按入口卷号查询。
|
||||||
|
*/
|
||||||
|
@GetMapping("/seg/{encoilId}")
|
||||||
|
public R<SqlServerApiBusinessService.SegSeriesView> segByEncoilId(@PathVariable String encoilId) {
|
||||||
|
return R.ok(businessService.getSegSeriesViewByEncoilId(encoilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 钢卷实际 SEG,按出口卷号查询。
|
||||||
|
*/
|
||||||
|
@GetMapping("/seg-by-excoil/{excoilId}")
|
||||||
|
public R<SqlServerApiBusinessService.SegSeriesView> segByExcoilId(@PathVariable String excoilId) {
|
||||||
|
return R.ok(businessService.getSegByExcoilId(excoilId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时数据:厚度、板形。
|
||||||
|
*/
|
||||||
|
@GetMapping("/realtime/{matId}")
|
||||||
|
public R<SqlServerApiBusinessService.RealtimeDataBundle> realtime(@PathVariable String matId) {
|
||||||
|
return R.ok(businessService.getRealtimeData(matId));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,6 +65,15 @@ user:
|
|||||||
# 密码锁定时间(默认10分钟)
|
# 密码锁定时间(默认10分钟)
|
||||||
lockTime: 10
|
lockTime: 10
|
||||||
|
|
||||||
|
# sql-server-api 中间件配置
|
||||||
|
sql-server-api:
|
||||||
|
# 请求地址,请替换为实际 IP
|
||||||
|
host: 127.0.0.1
|
||||||
|
# 请求端口,请替换为实际端口
|
||||||
|
port: 8080
|
||||||
|
# 基础访问地址(可直接注入使用)
|
||||||
|
base-url: http://${sql-server-api.host}:${sql-server-api.port}
|
||||||
|
|
||||||
# Spring配置
|
# Spring配置
|
||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
|
|||||||
36
klp-ui/src/api/l2/timing.js
Normal file
36
klp-ui/src/api/l2/timing.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
export default function createTimingFetch(url) {
|
||||||
|
const request = axios.create({
|
||||||
|
baseURL: 'http://' + url,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
timeout: 10000
|
||||||
|
})
|
||||||
|
|
||||||
|
request.interceptors.response.use(response => response.data)
|
||||||
|
|
||||||
|
return {
|
||||||
|
getPlanList: () => request({
|
||||||
|
url: '/sql-server-api/plans',
|
||||||
|
method: 'get'
|
||||||
|
}),
|
||||||
|
getPlanDetail: (coilId) => request({
|
||||||
|
url: `/sql-server-api/plans/${coilId}`,
|
||||||
|
method: 'get'
|
||||||
|
}),
|
||||||
|
getSegByEncoilId: (encoilId) => request({
|
||||||
|
url: `/sql-server-api/seg/${encoilId}`,
|
||||||
|
method: 'get'
|
||||||
|
}),
|
||||||
|
getSegByExcoilId: (excoilId) => request({
|
||||||
|
url: `/sql-server-api/seg-by-excoil/${excoilId}`,
|
||||||
|
method: 'get'
|
||||||
|
}),
|
||||||
|
getRealtimeData: (matId) => request({
|
||||||
|
url: `/sql-server-api/realtime/${matId}`,
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
189
klp-ui/src/views/timing/acid/index.vue
Normal file
189
klp-ui/src/views/timing/acid/index.vue
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
<template>
|
||||||
|
<div class="timing-page acid-page">
|
||||||
|
<el-card class="page-card" shadow="never">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span>酸轧实绩页</span>
|
||||||
|
<el-tag type="success" size="mini">Plan + Seg + Quality</el-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form :inline="true" :model="queryForm" size="mini" class="query-form">
|
||||||
|
<el-form-item label="计划号">
|
||||||
|
<el-input v-model="queryForm.coilId" placeholder="输入 coilId" clearable style="width: 220px;" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-search" :loading="loading" @click="handleSearch">查询</el-button>
|
||||||
|
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card shadow="never" class="sub-card">
|
||||||
|
<div slot="header" class="sub-header">计划列表</div>
|
||||||
|
<el-table
|
||||||
|
:data="planRows"
|
||||||
|
height="560"
|
||||||
|
size="mini"
|
||||||
|
highlight-current-row
|
||||||
|
@row-click="handlePlanRowClick"
|
||||||
|
>
|
||||||
|
<el-table-column prop="COILID" label="COILID" min-width="140" />
|
||||||
|
<el-table-column prop="HOT_COILID" label="热卷号" min-width="140" />
|
||||||
|
<el-table-column prop="STATUS" label="状态" width="90" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-card shadow="never" class="sub-card">
|
||||||
|
<div slot="header" class="sub-header">计划详情</div>
|
||||||
|
<el-empty v-if="!selectedPlan" description="请选择一条计划" />
|
||||||
|
<el-descriptions v-else :column="3" border size="mini">
|
||||||
|
<el-descriptions-item label="COILID">{{ selectedPlan.COILID }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="HOT_COILID">{{ selectedPlan.HOT_COILID }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="STATUS">{{ selectedPlan.STATUS }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="ENTRY_THICK">{{ selectedPlan.ENTRY_THICK }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="ENTRY_WIDTH">{{ selectedPlan.ENTRY_WIDTH }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="ENTRY_WEIGHT">{{ selectedPlan.ENTRY_WEIGHT }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="EXIT_THICK">{{ selectedPlan.EXIT_THICK }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="EXIT_WIDTH">{{ selectedPlan.EXIT_WIDTH }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="EXIT_LENGTH">{{ selectedPlan.EXIT_LENGTH }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-card>
|
||||||
|
|
||||||
|
<el-card shadow="never" class="sub-card" style="margin-top: 16px;">
|
||||||
|
<div slot="header" class="sub-header">SEG 实绩</div>
|
||||||
|
<el-alert
|
||||||
|
v-if="!segView"
|
||||||
|
title="请选择计划后自动加载对应 SEG"
|
||||||
|
type="info"
|
||||||
|
:closable="false"
|
||||||
|
show-icon
|
||||||
|
/>
|
||||||
|
<template v-else>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="8">
|
||||||
|
<el-card shadow="never">
|
||||||
|
<div slot="header">SEGNO</div>
|
||||||
|
<div class="seg-list">
|
||||||
|
<el-tag
|
||||||
|
v-for="item in segView.segNo"
|
||||||
|
:key="item"
|
||||||
|
size="mini"
|
||||||
|
class="seg-tag"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="16">
|
||||||
|
<el-card shadow="never">
|
||||||
|
<div slot="header">属性数组</div>
|
||||||
|
<el-table :data="seriesTable" size="mini" height="240" border>
|
||||||
|
<el-table-column prop="key" label="属性" width="180" />
|
||||||
|
<el-table-column prop="values" label="数组值" min-width="300">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<el-tag v-for="(item, index) in scope.row.values" :key="index" size="mini" style="margin-right: 4px; margin-bottom: 4px;">
|
||||||
|
{{ item }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import createTimingFetch from '@/api/l2/timing'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TimingAcidPage',
|
||||||
|
props: {
|
||||||
|
baseURL: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetchApi: null,
|
||||||
|
loading: false,
|
||||||
|
queryForm: { coilId: '' },
|
||||||
|
planRows: [],
|
||||||
|
selectedPlan: null,
|
||||||
|
segView: null,
|
||||||
|
seriesTable: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchApi = createTimingFetch(this.baseURL)
|
||||||
|
this.loadPlanList()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async loadPlanList() {
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await this.fetchApi.getPlanList()
|
||||||
|
const rows = res?.data?.rows || res?.rows || []
|
||||||
|
this.planRows = rows
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handleSearch() {
|
||||||
|
if (!this.queryForm.coilId) {
|
||||||
|
return this.loadPlanList()
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await this.fetchApi.getPlanDetail(this.queryForm.coilId)
|
||||||
|
const row = res?.data?.firstRow || res?.firstRow || null
|
||||||
|
this.selectedPlan = row
|
||||||
|
if (row && row.ENCOILID) {
|
||||||
|
await this.loadSeg(row.ENCOILID)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async handlePlanRowClick(row) {
|
||||||
|
this.selectedPlan = row
|
||||||
|
if (row?.COILID) {
|
||||||
|
const detail = await this.fetchApi.getPlanDetail(row.COILID)
|
||||||
|
const plan = detail?.data?.firstRow || detail?.firstRow || row
|
||||||
|
this.selectedPlan = plan
|
||||||
|
const encoilId = plan.ENCOILID || plan.ENCOILID || plan.COILID
|
||||||
|
if (encoilId) await this.loadSeg(encoilId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async loadSeg(encoilId) {
|
||||||
|
const res = await this.fetchApi.getSegByEncoilId(encoilId)
|
||||||
|
const view = res?.data || res
|
||||||
|
this.segView = view
|
||||||
|
this.seriesTable = Object.entries(view?.series || {}).map(([key, values]) => ({ key, values }))
|
||||||
|
},
|
||||||
|
handleReset() {
|
||||||
|
this.queryForm.coilId = ''
|
||||||
|
this.selectedPlan = null
|
||||||
|
this.segView = null
|
||||||
|
this.seriesTable = []
|
||||||
|
this.loadPlanList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.timing-page { padding: 16px; }
|
||||||
|
.page-card { border-radius: 12px; }
|
||||||
|
.card-header, .sub-header { display: flex; align-items: center; justify-content: space-between; font-weight: 600; }
|
||||||
|
.sub-card { border-radius: 10px; }
|
||||||
|
.query-form { margin-bottom: 12px; }
|
||||||
|
.seg-list { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||||
|
.seg-tag { margin-right: 0; }
|
||||||
|
</style>
|
||||||
110
klp-ui/src/views/timing/realtime/index.vue
Normal file
110
klp-ui/src/views/timing/realtime/index.vue
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
<template>
|
||||||
|
<div class="timing-page realtime-page">
|
||||||
|
<el-card shadow="never" class="page-card">
|
||||||
|
<div slot="header" class="card-header">
|
||||||
|
<span>实时跟踪页</span>
|
||||||
|
<el-tag type="warning" size="mini">Gauge + Shape</el-tag>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-form :inline="true" :model="queryForm" size="mini" class="query-form">
|
||||||
|
<el-form-item label="MATID">
|
||||||
|
<el-input v-model="queryForm.matId" placeholder="输入 MATID" clearable style="width: 240px;" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-button type="primary" icon="el-icon-refresh" :loading="loading" @click="handleQuery">获取实时数据</el-button>
|
||||||
|
<el-button icon="el-icon-delete" @click="handleReset">清空</el-button>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
|
||||||
|
<el-empty v-if="!realtimeData" description="请输入 MATID 后查询实时数据" />
|
||||||
|
|
||||||
|
<template v-else>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card shadow="never" class="sub-card">
|
||||||
|
<div slot="header">Gauge 厚度数据</div>
|
||||||
|
<el-table :data="gaugeRows" size="mini" height="520" border>
|
||||||
|
<el-table-column prop="XTIME" label="XTIME" width="120" />
|
||||||
|
<el-table-column prop="XLOCATION" label="XLOCATION" width="100" />
|
||||||
|
<el-table-column prop="THICK0" label="THICK0" width="90" />
|
||||||
|
<el-table-column prop="THICK1" label="THICK1" width="90" />
|
||||||
|
<el-table-column prop="THICK4" label="THICK4" width="90" />
|
||||||
|
<el-table-column prop="THICK5" label="THICK5" width="90" />
|
||||||
|
<el-table-column prop="EXIT_SPEED" label="EXIT_SPEED" width="100" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-card shadow="never" class="sub-card">
|
||||||
|
<div slot="header">Shape 板形数据</div>
|
||||||
|
<el-table :data="shapeRows" size="mini" height="520" border>
|
||||||
|
<el-table-column prop="XTIME" label="XTIME" width="120" />
|
||||||
|
<el-table-column prop="XLOCATION" label="XLOCATION" width="100" />
|
||||||
|
<el-table-column prop="HIGHZONEID" label="HIGHZONEID" width="100" />
|
||||||
|
<el-table-column prop="LOWZONEID" label="LOWZONEID" width="100" />
|
||||||
|
<el-table-column prop="EXIT_SPEED" label="EXIT_SPEED" width="100" />
|
||||||
|
<el-table-column prop="ROLLFORCE" label="ROLLFORCE" width="100" />
|
||||||
|
<el-table-column prop="ABSDEVIATION" label="ABSDEVIATION" width="110" />
|
||||||
|
</el-table>
|
||||||
|
</el-card>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</template>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import createTimingFetch from '@/api/l2/timing'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'TimingRealtimePage',
|
||||||
|
props: {
|
||||||
|
baseURL: { type: String, required: true }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetchApi: null,
|
||||||
|
loading: false,
|
||||||
|
queryForm: { matId: '' },
|
||||||
|
realtimeData: null,
|
||||||
|
gaugeRows: [],
|
||||||
|
shapeRows: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.fetchApi = createTimingFetch(this.baseURL)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
async handleQuery() {
|
||||||
|
if (!this.queryForm.matId) {
|
||||||
|
this.$message.warning('请输入 MATID')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.loading = true
|
||||||
|
try {
|
||||||
|
const res = await this.fetchApi.getRealtimeData(this.queryForm.matId)
|
||||||
|
this.realtimeData = res?.data || res
|
||||||
|
this.gaugeRows = this.realtimeData?.gauge?.result || []
|
||||||
|
this.shapeRows = this.realtimeData?.shape?.result || []
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handleReset() {
|
||||||
|
this.queryForm.matId = ''
|
||||||
|
this.realtimeData = null
|
||||||
|
this.gaugeRows = []
|
||||||
|
this.shapeRows = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.timing-page { padding: 16px; }
|
||||||
|
.page-card { border-radius: 12px; }
|
||||||
|
.card-header { display: flex; align-items: center; justify-content: space-between; font-weight: 600; }
|
||||||
|
.query-form { margin-bottom: 12px; }
|
||||||
|
.sub-card { border-radius: 10px; }
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user