From 974c7aa4010d77bb410b99931b4435d5442deb4b Mon Sep 17 00:00:00 2001
From: zhuguifei <312353457@qq.com>
Date: 星期一, 02 三月 2026 12:55:52 +0800
Subject: [PATCH] feat(module(qa)): 新增
---
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/MakeupTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PointDataMapper.java | 9
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IHoisterTimeDataService.java | 7
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/FeedmatchTimeDataMapper.java | 9
ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue | 373 ++++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/HoisterTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/BoxTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/FeedmatchTimeDataServiceImpl.java | 11
TimescaleDB-Utils/HELP.md | 10
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/HoisterTimeDataMapper.java | 9
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/FeedmatchTimeData.java | 148 +
ruoyi-plus-soybean/src/service/api/qm/batch.ts | 35
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/MakeupTimeData.java | 78
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPackerTimeDataService.java | 7
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IMakeupTimeDataService.java | 7
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/controller/QmBatchController.java | 105 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/MybatisPlusConfig.java | 9
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/StartupStatusPrinter.java | 53
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IFeedmatchTimeDataService.java | 7
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IRollerTimeDataService.java | 7
TimescaleDB-Utils/src/main/resources/application.yml | 37
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/impl/QmBatchServiceImpl.java | 144 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/RollerTimeDataMapper.java | 9
.gitignore | 4
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/MakeupTimeDataMapper.java | 9
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qm/QmBatchMapper.xml | 6
TimescaleDB-Utils/pom.xml | 98 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PackerTimeDataMapper.java | 9
ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts | 185 ++
TimescaleDB-Utils/readMe.md | 509 ++++++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/TransTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/RollerTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PackerTimeDataServiceImpl.java | 11
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/BoxTimeDataMapper.java | 9
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/IQmBatchService.java | 68
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PointDataServiceImpl.java | 11
TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/RollerTimeDataTest.java | 29
ruoyi-plus-soybean/src/views/qm/batch/index.vue | 474 +++++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/TransTimeDataMapper.java | 9
TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplicationTests.java | 40
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/constant/AppConstants.java | 92 +
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/vo/QmBatchVo.java | 316 +++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplication.java | 23
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/task/RedisToPostgresSyncTask.java | 278 +++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PackerTimeData.java | 138 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/ITransTimeDataService.java | 7
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/HoisterTimeData.java | 208 ++
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/QmBatch.java | 263 +++
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPointDataService.java | 7
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PointData.java | 53
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/RollerTimeData.java | 118 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IBoxTimeDataService.java | 7
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/mapper/QmBatchMapper.java | 15
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/BoxTimeData.java | 53
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/utils/RedisUtils.java | 114 +
ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue | 150 +
TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/TransTimeData.java | 153 +
RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/bo/QmBatchBo.java | 262 +++
TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/PostgresDataMonitorTest.java | 80
59 files changed, 4,937 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..440a664
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+**/.idea
+**/logs
+**/target
+**/.vscode
\ No newline at end of file
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/controller/QmBatchController.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/controller/QmBatchController.java
new file mode 100644
index 0000000..fba4085
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/controller/QmBatchController.java
@@ -0,0 +1,105 @@
+package org.dromara.qm.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.qm.domain.vo.QmBatchVo;
+import org.dromara.qm.domain.bo.QmBatchBo;
+import org.dromara.qm.service.IQmBatchService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 妫�楠屾壒娆�
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/qm/batch")
+public class QmBatchController extends BaseController {
+
+ private final IQmBatchService qmBatchService;
+
+ /**
+ * 鏌ヨ妫�楠屾壒娆″垪琛�
+ */
+ @SaCheckPermission("qm:batch:list")
+ @GetMapping("/list")
+ public TableDataInfo<QmBatchVo> list(QmBatchBo bo, PageQuery pageQuery) {
+ return qmBatchService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭妫�楠屾壒娆″垪琛�
+ */
+ @SaCheckPermission("qm:batch:export")
+ @Log(title = "妫�楠屾壒娆�", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(QmBatchBo bo, HttpServletResponse response) {
+ List<QmBatchVo> list = qmBatchService.queryList(bo);
+ ExcelUtil.exportExcel(list, "妫�楠屾壒娆�", QmBatchVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇妫�楠屾壒娆¤缁嗕俊鎭�
+ *
+ * @param id 涓婚敭
+ */
+ @SaCheckPermission("qm:batch:query")
+ @GetMapping("/{id}")
+ public R<QmBatchVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable String id) {
+ return R.ok(qmBatchService.queryById(id));
+ }
+
+ /**
+ * 鏂板妫�楠屾壒娆�
+ */
+ @SaCheckPermission("qm:batch:add")
+ @Log(title = "妫�楠屾壒娆�", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody QmBatchBo bo) {
+ return toAjax(qmBatchService.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼妫�楠屾壒娆�
+ */
+ @SaCheckPermission("qm:batch:edit")
+ @Log(title = "妫�楠屾壒娆�", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody QmBatchBo bo) {
+ return toAjax(qmBatchService.updateByBo(bo));
+ }
+
+ /**
+ * 鍒犻櫎妫�楠屾壒娆�
+ *
+ * @param ids 涓婚敭涓�
+ */
+ @SaCheckPermission("qm:batch:remove")
+ @Log(title = "妫�楠屾壒娆�", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable String[] ids) {
+ return toAjax(qmBatchService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/QmBatch.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/QmBatch.java
new file mode 100644
index 0000000..709a2ae
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/QmBatch.java
@@ -0,0 +1,263 @@
+package org.dromara.qm.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 妫�楠屾壒娆″璞� qm_batch
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("qm_batch")
+public class QmBatch extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 缂栫爜
+ */
+ @TableId(value = "id")
+ private String id;
+
+ /**
+ * 鎵规浠g爜
+ */
+ private String batchCode;
+
+ /**
+ * 鎵规鍚嶇О
+ */
+ private String batchName;
+
+ /**
+ * A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
+ */
+ private String typ;
+
+ /**
+ * 鏈哄彴浠g爜
+ */
+ private String eqpCode;
+
+ /**
+ * 鐗屽彿
+ */
+ private String matCode;
+
+ /**
+ * 鍒ゅ畾渚濇嵁浠g爜
+ */
+ private String judgeCode;
+
+ /**
+ * 鎵规鐢熸垚鏃ユ湡
+ */
+ private Date batchDate;
+
+ /**
+ * 浣跨敤鏍囧織
+ */
+ private String isflag;
+
+ /**
+ * 鍚敤鏍囧織
+ */
+ private String enabled;
+
+ /**
+ * 鍒拌揣鎬婚噺
+ */
+ private Long totalNum;
+
+ /**
+ * 缁煎悎鍒ゅ畾
+ */
+ private String results;
+
+ /**
+ * 鎵瑰噯浜�
+ */
+ private String approver;
+
+ /**
+ * 瀹℃牳浜�
+ */
+ private String auditor;
+
+ /**
+ * 鍒涘缓浜�
+ */
+ private String creater;
+
+ /**
+ * 鍒惰〃鏃ユ湡
+ */
+ private Date tabDate;
+
+ /**
+ * 鐗堟湰鍚嶇О
+ */
+ private String verName;
+
+ /**
+ * 鐗堟湰缂栧彿
+ */
+ private String verCode;
+
+ /**
+ * 淇濆瓨鏈�
+ */
+ private String archDate;
+
+ /**
+ * 0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇
+ */
+ private String flag;
+
+ /**
+ * 涓婁紶MES鏃堕棿
+ */
+ private Date toMesDate;
+
+ /**
+ * 浠嶮ES鏃堕棿涓嬭浇
+ */
+ private Date fromMesDate;
+
+ /**
+ * 鍒犻櫎鏍囧織
+ */
+ private Long deleted;
+
+ /**
+ * 鎵规鎻忚堪
+ */
+ private String batchDes;
+
+ /**
+ * 绫诲埆 0锛氭垚鍝� 1锛氳緟鏉�
+ */
+ private String category;
+
+ /**
+ * 鍗峰埗宸ュ彿
+ */
+ private String makeno;
+
+ /**
+ * 鐝鏈哄彿
+ */
+ private String shifteqpno;
+
+ /**
+ * 瑁呯鍙�
+ */
+ private String boxno;
+
+ /**
+ * 鐖舵壒娆″彿
+ */
+ private String pid;
+
+ /**
+ * 澶嶆牳浜�
+ */
+ private String reviewer;
+
+ /**
+ * 澶嶆娆℃暟
+ */
+ private Long rvcount;
+
+ /**
+ * 鎵规鐘舵��
+ */
+ private String state;
+
+ /**
+ * 澶嶆牳鏃ユ湡
+ */
+ private Date reviewTime;
+
+ /**
+ * 瀹℃牳鏃ユ湡
+ */
+ private Date auditTime;
+
+ /**
+ * 瑙勬牸
+ */
+ private String spec;
+
+ /**
+ * 鎵瑰噯鏃堕棿
+ */
+ private Date approveTime;
+
+ /**
+ * 鍒拌揣鍗曚綅
+ */
+ private String unit;
+
+ /**
+ * 鍒拌揣鏃ユ湡
+ */
+ private Date arrivalTime;
+
+ /**
+ * 瀛樻斁鍦扮偣
+ */
+ private String storagePlace;
+
+ /**
+ * 妫�楠屽憳
+ */
+ private String checker;
+
+ /**
+ * 鎺ュ崟鏃ユ湡
+ */
+ private Date receiveTime;
+
+ /**
+ * 鎶ユ鏃ユ湡
+ */
+ private Date inspTime;
+
+ /**
+ * 浠撳簱淇濈鍛�
+ */
+ private String storer;
+
+ /**
+ * 鏄惁楠岃瘉
+ */
+ private String isverify;
+
+ /**
+ * 鏄惁妫�楠�
+ */
+ private String ischk;
+
+ /**
+ * 澶囩敤1
+ */
+ private String bak1;
+
+ /**
+ * 澶囩敤2
+ */
+ private String bak2;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/bo/QmBatchBo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/bo/QmBatchBo.java
new file mode 100644
index 0000000..36bf7af
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/bo/QmBatchBo.java
@@ -0,0 +1,262 @@
+package org.dromara.qm.domain.bo;
+
+import org.dromara.qm.domain.QmBatch;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 妫�楠屾壒娆′笟鍔″璞� qm_batch
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = QmBatch.class, reverseConvertGenerate = false)
+public class QmBatchBo extends BaseEntity {
+
+ /**
+ * 缂栫爜
+ */
+ @NotBlank(message = "缂栫爜涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private String id;
+
+ /**
+ * 鎵规浠g爜
+ */
+ private String batchCode;
+
+ /**
+ * 鎵规鍚嶇О
+ */
+ private String batchName;
+
+ /**
+ * A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
+ */
+ private String typ;
+
+ /**
+ * 鏈哄彴浠g爜
+ */
+ private String eqpCode;
+
+ /**
+ * 鐗屽彿
+ */
+ private String matCode;
+
+ /**
+ * 鍒ゅ畾渚濇嵁浠g爜
+ */
+ private String judgeCode;
+
+ /**
+ * 鎵规鐢熸垚鏃ユ湡
+ */
+ private Date batchDate;
+
+ /**
+ * 浣跨敤鏍囧織
+ */
+ private String isflag;
+
+ /**
+ * 鍚敤鏍囧織
+ */
+ private String enabled;
+
+ /**
+ * 鍒拌揣鎬婚噺
+ */
+ private Long totalNum;
+
+ /**
+ * 缁煎悎鍒ゅ畾
+ */
+ private String results;
+
+ /**
+ * 鎵瑰噯浜�
+ */
+ private String approver;
+
+ /**
+ * 瀹℃牳浜�
+ */
+ private String auditor;
+
+ /**
+ * 鍒涘缓浜�
+ */
+ private String creater;
+
+ /**
+ * 鍒惰〃鏃ユ湡
+ */
+ private Date tabDate;
+
+ /**
+ * 鐗堟湰鍚嶇О
+ */
+ private String verName;
+
+ /**
+ * 鐗堟湰缂栧彿
+ */
+ private String verCode;
+
+ /**
+ * 淇濆瓨鏈�
+ */
+ private String archDate;
+
+ /**
+ * 0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇
+ */
+ private String flag;
+
+ /**
+ * 涓婁紶MES鏃堕棿
+ */
+ private Date toMesDate;
+
+ /**
+ * 浠嶮ES鏃堕棿涓嬭浇
+ */
+ private Date fromMesDate;
+
+ /**
+ * 鍒犻櫎鏍囧織
+ */
+ private Long deleted;
+
+ /**
+ * 鎵规鎻忚堪
+ */
+ private String batchDes;
+
+ /**
+ * 绫诲埆 0锛氭垚鍝� 1锛氳緟鏉�
+ */
+ private String category;
+
+ /**
+ * 鍗峰埗宸ュ彿
+ */
+ private String makeno;
+
+ /**
+ * 鐝鏈哄彿
+ */
+ private String shifteqpno;
+
+ /**
+ * 瑁呯鍙�
+ */
+ private String boxno;
+
+ /**
+ * 鐖舵壒娆″彿
+ */
+ private String pid;
+
+ /**
+ * 澶嶆牳浜�
+ */
+ private String reviewer;
+
+ /**
+ * 澶嶆娆℃暟
+ */
+ private Long rvcount;
+
+ /**
+ * 鎵规鐘舵��
+ */
+ private String state;
+
+ /**
+ * 澶嶆牳鏃ユ湡
+ */
+ private Date reviewTime;
+
+ /**
+ * 瀹℃牳鏃ユ湡
+ */
+ private Date auditTime;
+
+ /**
+ * 瑙勬牸
+ */
+ private String spec;
+
+ /**
+ * 鎵瑰噯鏃堕棿
+ */
+ private Date approveTime;
+
+ /**
+ * 鍒拌揣鍗曚綅
+ */
+ private String unit;
+
+ /**
+ * 鍒拌揣鏃ユ湡
+ */
+ private Date arrivalTime;
+
+ /**
+ * 瀛樻斁鍦扮偣
+ */
+ private String storagePlace;
+
+ /**
+ * 妫�楠屽憳
+ */
+ private String checker;
+
+ /**
+ * 鎺ュ崟鏃ユ湡
+ */
+ private Date receiveTime;
+
+ /**
+ * 鎶ユ鏃ユ湡
+ */
+ private Date inspTime;
+
+ /**
+ * 浠撳簱淇濈鍛�
+ */
+ private String storer;
+
+ /**
+ * 鏄惁楠岃瘉
+ */
+ private String isverify;
+
+ /**
+ * 鏄惁妫�楠�
+ */
+ private String ischk;
+
+ /**
+ * 澶囩敤1
+ */
+ private String bak1;
+
+ /**
+ * 澶囩敤2
+ */
+ private String bak2;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/vo/QmBatchVo.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/vo/QmBatchVo.java
new file mode 100644
index 0000000..ae17bed
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/domain/vo/QmBatchVo.java
@@ -0,0 +1,316 @@
+package org.dromara.qm.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.qm.domain.QmBatch;
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 妫�楠屾壒娆¤鍥惧璞� qm_batch
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = QmBatch.class)
+public class QmBatchVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 缂栫爜
+ */
+ @ExcelProperty(value = "缂栫爜")
+ private String id;
+
+ /**
+ * 鎵规浠g爜
+ */
+ @ExcelProperty(value = "鎵规浠g爜")
+ private String batchCode;
+
+ /**
+ * 鎵规鍚嶇О
+ */
+ @ExcelProperty(value = "鎵规鍚嶇О")
+ private String batchName;
+
+ /**
+ * A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
+ */
+ @ExcelProperty(value = "A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�")
+ private String typ;
+
+ /**
+ * 鏈哄彴浠g爜
+ */
+ @ExcelProperty(value = "鏈哄彴浠g爜")
+ private String eqpCode;
+
+ /**
+ * 鐗屽彿
+ */
+ @ExcelProperty(value = "鐗屽彿")
+ private String matCode;
+
+ /**
+ * 鍒ゅ畾渚濇嵁浠g爜
+ */
+ @ExcelProperty(value = "鍒ゅ畾渚濇嵁浠g爜")
+ private String judgeCode;
+
+ /**
+ * 鎵规鐢熸垚鏃ユ湡
+ */
+ @ExcelProperty(value = "鎵规鐢熸垚鏃ユ湡")
+ private Date batchDate;
+
+ /**
+ * 浣跨敤鏍囧織
+ */
+ @ExcelProperty(value = "浣跨敤鏍囧織")
+ private String isflag;
+
+ /**
+ * 鍚敤鏍囧織
+ */
+ @ExcelProperty(value = "鍚敤鏍囧織")
+ private String enabled;
+
+ /**
+ * 鍒拌揣鎬婚噺
+ */
+ @ExcelProperty(value = "鍒拌揣鎬婚噺")
+ private Long totalNum;
+
+ /**
+ * 缁煎悎鍒ゅ畾
+ */
+ @ExcelProperty(value = "缁煎悎鍒ゅ畾")
+ private String results;
+
+ /**
+ * 鎵瑰噯浜�
+ */
+ @ExcelProperty(value = "鎵瑰噯浜�")
+ private String approver;
+
+ /**
+ * 瀹℃牳浜�
+ */
+ @ExcelProperty(value = "瀹℃牳浜�")
+ private String auditor;
+
+ /**
+ * 鍒涘缓浜�
+ */
+ @ExcelProperty(value = "鍒涘缓浜�")
+ private String creater;
+
+ /**
+ * 鍒惰〃鏃ユ湡
+ */
+ @ExcelProperty(value = "鍒惰〃鏃ユ湡")
+ private Date tabDate;
+
+ /**
+ * 鐗堟湰鍚嶇О
+ */
+ @ExcelProperty(value = "鐗堟湰鍚嶇О")
+ private String verName;
+
+ /**
+ * 鐗堟湰缂栧彿
+ */
+ @ExcelProperty(value = "鐗堟湰缂栧彿")
+ private String verCode;
+
+ /**
+ * 淇濆瓨鏈�
+ */
+ @ExcelProperty(value = "淇濆瓨鏈�")
+ private String archDate;
+
+ /**
+ * 0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇
+ */
+ @ExcelProperty(value = "0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇")
+ private String flag;
+
+ /**
+ * 涓婁紶MES鏃堕棿
+ */
+ @ExcelProperty(value = "涓婁紶MES鏃堕棿")
+ private Date toMesDate;
+
+ /**
+ * 浠嶮ES鏃堕棿涓嬭浇
+ */
+ @ExcelProperty(value = "浠嶮ES鏃堕棿涓嬭浇")
+ private Date fromMesDate;
+
+ /**
+ * 鍒犻櫎鏍囧織
+ */
+ @ExcelProperty(value = "鍒犻櫎鏍囧織")
+ private Long deleted;
+
+ /**
+ * 鎵规鎻忚堪
+ */
+ @ExcelProperty(value = "鎵规鎻忚堪")
+ private String batchDes;
+
+ /**
+ * 绫诲埆 0锛氭垚鍝� 1锛氳緟鏉�
+ */
+ @ExcelProperty(value = "绫诲埆 0锛氭垚鍝� 1锛氳緟鏉�")
+ private String category;
+
+ /**
+ * 鍗峰埗宸ュ彿
+ */
+ @ExcelProperty(value = "鍗峰埗宸ュ彿")
+ private String makeno;
+
+ /**
+ * 鐝鏈哄彿
+ */
+ @ExcelProperty(value = "鐝鏈哄彿")
+ private String shifteqpno;
+
+ /**
+ * 瑁呯鍙�
+ */
+ @ExcelProperty(value = "瑁呯鍙�")
+ private String boxno;
+
+ /**
+ * 鐖舵壒娆″彿
+ */
+ @ExcelProperty(value = "鐖舵壒娆″彿")
+ private String pid;
+
+ /**
+ * 澶嶆牳浜�
+ */
+ @ExcelProperty(value = "澶嶆牳浜�")
+ private String reviewer;
+
+ /**
+ * 澶嶆娆℃暟
+ */
+ @ExcelProperty(value = "澶嶆娆℃暟")
+ private Long rvcount;
+
+ /**
+ * 鎵规鐘舵��
+ */
+ @ExcelProperty(value = "鎵规鐘舵��")
+ private String state;
+
+ /**
+ * 澶嶆牳鏃ユ湡
+ */
+ @ExcelProperty(value = "澶嶆牳鏃ユ湡")
+ private Date reviewTime;
+
+ /**
+ * 瀹℃牳鏃ユ湡
+ */
+ @ExcelProperty(value = "瀹℃牳鏃ユ湡")
+ private Date auditTime;
+
+ /**
+ * 瑙勬牸
+ */
+ @ExcelProperty(value = "瑙勬牸")
+ private String spec;
+
+ /**
+ * 鎵瑰噯鏃堕棿
+ */
+ @ExcelProperty(value = "鎵瑰噯鏃堕棿")
+ private Date approveTime;
+
+ /**
+ * 鍒拌揣鍗曚綅
+ */
+ @ExcelProperty(value = "鍒拌揣鍗曚綅")
+ private String unit;
+
+ /**
+ * 鍒拌揣鏃ユ湡
+ */
+ @ExcelProperty(value = "鍒拌揣鏃ユ湡")
+ private Date arrivalTime;
+
+ /**
+ * 瀛樻斁鍦扮偣
+ */
+ @ExcelProperty(value = "瀛樻斁鍦扮偣")
+ private String storagePlace;
+
+ /**
+ * 妫�楠屽憳
+ */
+ @ExcelProperty(value = "妫�楠屽憳")
+ private String checker;
+
+ /**
+ * 鎺ュ崟鏃ユ湡
+ */
+ @ExcelProperty(value = "鎺ュ崟鏃ユ湡")
+ private Date receiveTime;
+
+ /**
+ * 鎶ユ鏃ユ湡
+ */
+ @ExcelProperty(value = "鎶ユ鏃ユ湡")
+ private Date inspTime;
+
+ /**
+ * 浠撳簱淇濈鍛�
+ */
+ @ExcelProperty(value = "浠撳簱淇濈鍛�")
+ private String storer;
+
+ /**
+ * 鏄惁楠岃瘉
+ */
+ @ExcelProperty(value = "鏄惁楠岃瘉")
+ private String isverify;
+
+ /**
+ * 鏄惁妫�楠�
+ */
+ @ExcelProperty(value = "鏄惁妫�楠�")
+ private String ischk;
+
+ /**
+ * 澶囩敤1
+ */
+ @ExcelProperty(value = "澶囩敤1")
+ private String bak1;
+
+ /**
+ * 澶囩敤2
+ */
+ @ExcelProperty(value = "澶囩敤2")
+ private String bak2;
+
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/mapper/QmBatchMapper.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/mapper/QmBatchMapper.java
new file mode 100644
index 0000000..0539e73
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/mapper/QmBatchMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.qm.mapper;
+
+import org.dromara.qm.domain.QmBatch;
+import org.dromara.qm.domain.vo.QmBatchVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 妫�楠屾壒娆apper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+public interface QmBatchMapper extends BaseMapperPlus<QmBatch, QmBatchVo> {
+
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/IQmBatchService.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/IQmBatchService.java
new file mode 100644
index 0000000..5d99bea
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/IQmBatchService.java
@@ -0,0 +1,68 @@
+package org.dromara.qm.service;
+
+import org.dromara.qm.domain.vo.QmBatchVo;
+import org.dromara.qm.domain.bo.QmBatchBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 妫�楠屾壒娆ervice鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+public interface IQmBatchService {
+
+ /**
+ * 鏌ヨ妫�楠屾壒娆�
+ *
+ * @param id 涓婚敭
+ * @return 妫�楠屾壒娆�
+ */
+ QmBatchVo queryById(String id);
+
+ /**
+ * 鍒嗛〉鏌ヨ妫�楠屾壒娆″垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @param pageQuery 鍒嗛〉鍙傛暟
+ * @return 妫�楠屾壒娆″垎椤靛垪琛�
+ */
+ TableDataInfo<QmBatchVo> queryPageList(QmBatchBo bo, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ绗﹀悎鏉′欢鐨勬楠屾壒娆″垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @return 妫�楠屾壒娆″垪琛�
+ */
+ List<QmBatchVo> queryList(QmBatchBo bo);
+
+ /**
+ * 鏂板妫�楠屾壒娆�
+ *
+ * @param bo 妫�楠屾壒娆�
+ * @return 鏄惁鏂板鎴愬姛
+ */
+ Boolean insertByBo(QmBatchBo bo);
+
+ /**
+ * 淇敼妫�楠屾壒娆�
+ *
+ * @param bo 妫�楠屾壒娆�
+ * @return 鏄惁淇敼鎴愬姛
+ */
+ Boolean updateByBo(QmBatchBo bo);
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄ゆ楠屾壒娆′俊鎭�
+ *
+ * @param ids 寰呭垹闄ょ殑涓婚敭闆嗗悎
+ * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+ * @return 鏄惁鍒犻櫎鎴愬姛
+ */
+ Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid);
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/impl/QmBatchServiceImpl.java b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/impl/QmBatchServiceImpl.java
new file mode 100644
index 0000000..afa7942
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/java/org/dromara/qm/service/impl/QmBatchServiceImpl.java
@@ -0,0 +1,144 @@
+package org.dromara.qm.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.dromara.qm.domain.bo.QmBatchBo;
+import org.dromara.qm.domain.vo.QmBatchVo;
+import org.dromara.qm.domain.QmBatch;
+import org.dromara.qm.mapper.QmBatchMapper;
+import org.dromara.qm.service.IQmBatchService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 妫�楠屾壒娆ervice涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2026-03-02
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class QmBatchServiceImpl implements IQmBatchService {
+
+ private final QmBatchMapper baseMapper;
+
+ /**
+ * 鏌ヨ妫�楠屾壒娆�
+ *
+ * @param id 涓婚敭
+ * @return 妫�楠屾壒娆�
+ */
+ @Override
+ public QmBatchVo queryById(String id){
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 鍒嗛〉鏌ヨ妫�楠屾壒娆″垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @param pageQuery 鍒嗛〉鍙傛暟
+ * @return 妫�楠屾壒娆″垎椤靛垪琛�
+ */
+ @Override
+ public TableDataInfo<QmBatchVo> queryPageList(QmBatchBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<QmBatch> lqw = buildQueryWrapper(bo);
+ Page<QmBatchVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 鏌ヨ绗﹀悎鏉′欢鐨勬楠屾壒娆″垪琛�
+ *
+ * @param bo 鏌ヨ鏉′欢
+ * @return 妫�楠屾壒娆″垪琛�
+ */
+ @Override
+ public List<QmBatchVo> queryList(QmBatchBo bo) {
+ LambdaQueryWrapper<QmBatch> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<QmBatch> buildQueryWrapper(QmBatchBo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<QmBatch> lqw = Wrappers.lambdaQuery();
+ lqw.orderByAsc(QmBatch::getId);
+ lqw.like(StringUtils.isNotBlank(bo.getBatchCode()), QmBatch::getBatchCode, bo.getBatchCode());
+ lqw.eq(StringUtils.isNotBlank(bo.getTyp()), QmBatch::getTyp, bo.getTyp());
+ lqw.eq(StringUtils.isNotBlank(bo.getEqpCode()), QmBatch::getEqpCode, bo.getEqpCode());
+ lqw.eq(StringUtils.isNotBlank(bo.getMatCode()), QmBatch::getMatCode, bo.getMatCode());
+ lqw.eq(bo.getBatchDate() != null, QmBatch::getBatchDate, bo.getBatchDate());
+ lqw.eq(StringUtils.isNotBlank(bo.getFlag()), QmBatch::getFlag, bo.getFlag());
+ lqw.between(params.get("beginToMesDate") != null && params.get("endToMesDate") != null,
+ QmBatch::getToMesDate ,params.get("beginToMesDate"), params.get("endToMesDate"));
+ lqw.between(params.get("beginFromMesDate") != null && params.get("endFromMesDate") != null,
+ QmBatch::getFromMesDate ,params.get("beginFromMesDate"), params.get("endFromMesDate"));
+ lqw.eq(bo.getDeleted() != null, QmBatch::getDeleted, bo.getDeleted());
+ lqw.eq(StringUtils.isNotBlank(bo.getCategory()), QmBatch::getCategory, bo.getCategory());
+ lqw.eq(StringUtils.isNotBlank(bo.getState()), QmBatch::getState, bo.getState());
+ return lqw;
+ }
+
+ /**
+ * 鏂板妫�楠屾壒娆�
+ *
+ * @param bo 妫�楠屾壒娆�
+ * @return 鏄惁鏂板鎴愬姛
+ */
+ @Override
+ public Boolean insertByBo(QmBatchBo bo) {
+ QmBatch add = MapstructUtils.convert(bo, QmBatch.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 淇敼妫�楠屾壒娆�
+ *
+ * @param bo 妫�楠屾壒娆�
+ * @return 鏄惁淇敼鎴愬姛
+ */
+ @Override
+ public Boolean updateByBo(QmBatchBo bo) {
+ QmBatch update = MapstructUtils.convert(bo, QmBatch.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(QmBatch entity){
+ //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+ }
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄ゆ楠屾壒娆′俊鎭�
+ *
+ * @param ids 寰呭垹闄ょ殑涓婚敭闆嗗悎
+ * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+ * @return 鏄惁鍒犻櫎鎴愬姛
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
+ if(isValid){
+ //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+ }
+ return baseMapper.deleteByIds(ids) > 0;
+ }
+}
diff --git a/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qm/QmBatchMapper.xml b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qm/QmBatchMapper.xml
new file mode 100644
index 0000000..0092e5f
--- /dev/null
+++ b/RuoYi-Vue-Plus/ruoyi-modules/ruoyi-qa/src/main/resources/mapper/qm/QmBatchMapper.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.qm.mapper.QmBatchMapper">
+</mapper>
diff --git a/TimescaleDB-Utils/HELP.md b/TimescaleDB-Utils/HELP.md
new file mode 100755
index 0000000..b7509c2
--- /dev/null
+++ b/TimescaleDB-Utils/HELP.md
@@ -0,0 +1,10 @@
+# Getting Started
+
+### Reference Documentation
+
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/)
+* [Create an OCI image](https://docs.spring.io/spring-boot/docs/2.6.13/maven-plugin/reference/html/#build-image)
+
diff --git a/TimescaleDB-Utils/pom.xml b/TimescaleDB-Utils/pom.xml
new file mode 100755
index 0000000..2088e09
--- /dev/null
+++ b/TimescaleDB-Utils/pom.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.shlb</groupId>
+ <artifactId>TimescaleDB-Utils</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <name>TimescaleDB-Utils</name>
+ <description>TimescaleDB-Utils</description>
+ <properties>
+ <java.version>1.8</java.version>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <spring-boot.version>2.6.13</spring-boot.version>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>com.baomidou</groupId>
+ <artifactId>mybatis-plus-boot-starter</artifactId>
+ <version>3.5.3.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.postgresql</groupId>
+ <artifactId>postgresql</artifactId>
+ <scope>runtime</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-data-redis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>1.2.83</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-dependencies</artifactId>
+ <version>${spring-boot.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <configuration>
+ <mainClass>com.shlb.timescaledbutils.TimescaleDbUtilsApplication</mainClass>
+ </configuration>
+ <executions>
+ <execution>
+ <id>repackage</id>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/TimescaleDB-Utils/readMe.md b/TimescaleDB-Utils/readMe.md
new file mode 100755
index 0000000..1544f02
--- /dev/null
+++ b/TimescaleDB-Utils/readMe.md
@@ -0,0 +1,509 @@
+
+鐗瑰埆娉ㄦ剰锛�
+postgres鏃跺尯闂锛屽畨瑁呭悗濡傛灉鏄疷TC瑕佹敼鎴� Asia/Shanghai(+8)
+
+
+鍔ㄦ�佽繍琛屽弬鏁� my_new_key - > 闇�瑕佸瓨鍌ㄦ暟鎹簱鐨勪笂绾ey锛� sync-interval-ms - > 瀛樺偍鏃堕棿闂撮殧
+java -jar TimescaleDB-Utils.jar \
+--spring.redis.queue-key=my_new_key \
+--spring.redis.sync-interval-ms=2000
+
+
+
+//鍗锋帴鏈鸿〃
+-- 鍒涘缓涓昏〃
+CREATE TABLE roller_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL, -- 璁句负 NOT NULL 鍥犱负鎮ㄦ湁鍥哄畾鐨� key 鍒楄〃
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鎮ㄧ殑涓氬姟瀛楁
+ online INTEGER, -- 缃戠粶鐘舵��(0寮傚父 1姝e父)
+ qty DOUBLE PRECISION, -- 浜ч噺
+ bad_qty DOUBLE PRECISION, -- 鍓旈櫎浜ч噺
+ lvbang_val DOUBLE PRECISION, -- 婊ゆ娑堣��
+ juanyanzhi_val DOUBLE PRECISION, -- 鍗风儫绾告秷鑰�
+ shuisongzhi_val DOUBLE PRECISION, -- 姘存澗绾告秷鑰�
+ run_time DOUBLE PRECISION, -- 杩愯鏃堕棿
+ stop_time DOUBLE PRECISION, -- 鍋滄満鏃堕棿
+ stop_times INTEGER, -- 鍋滄満娆℃暟
+ speed INTEGER, -- 杞﹂��
+ run_status INTEGER, -- 杩愯鐘舵��(-1鏂綉 0鍋滄 1浣庨�熻繍琛� 2姝e父杩愯)
+ cy DOUBLE PRECISION, -- 鍌ㄧ儫璁惧鍌ㄩ噺
+ cy_cs INTEGER, -- 鍌ㄧ儫璁惧杞﹂��(1-鍖呰鏈� 6-鍗风儫鏈�)
+ cy_online TEXT, -- (22-鍗风儫鏈鸿繍琛岀姸鎬� 23-鍖呰鏈鸿繍琛岀姸鎬�)
+ rec_qty1 DOUBLE PRECISION, -- 鎺ユ敹鏈洪噺
+ rec_qty2 DOUBLE PRECISION -- 鎺ユ敹鏈洪噺2
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛屾寜key杩涜绌洪棿鍒嗗尯锛�
+SELECT create_hypertable(
+'roller_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛�
+-- 鍒嗘垚 8 涓垎鍖猴紝姣忎釜鍒嗗尯澶х害鍖呭惈 4-5 涓� key
+SELECT add_dimension(
+'roller_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓绱㈠紩浠ユ彁楂樻煡璇㈡�ц兘
+-- 澶嶅悎绱㈠紩锛岄�傚悎鎸夋椂闂村拰key鏌ヨ
+CREATE INDEX idx_roller_time_data_time_key ON roller_time_data (time DESC, key);
+-- 鍗曠嫭绱㈠紩锛岄�傚悎鎸塳ey鏌ヨ
+CREATE INDEX idx_roller_time_data_key_time ON roller_time_data (key, time DESC);
+-- 涓氬姟鏌ヨ甯哥敤瀛楁绱㈠紩
+CREATE INDEX idx_roller_time_data_run_status_key ON roller_time_data (run_status, key, time DESC);
+CREATE INDEX idx_roller_time_data_online_key ON roller_time_data (online, key, time DESC);
+CREATE INDEX idx_roller_time_data_speed_key ON roller_time_data (speed, key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_roller_time_data_shift ON roller_time_data (shift);
+CREATE INDEX idx_roller_time_data_equ_no ON roller_time_data (equ_no);
+
+-- 鍙�夛細濡傛灉鏌愪簺璁惧鏁版嵁閲忕壒鍒ぇ锛屽彲浠ヤ负鐗瑰畾璁惧鍒涘缓涓撶敤绱㈠紩
+-- CREATE INDEX idx_roller_1101 ON roller_time_data (time DESC) WHERE key = '1101';
+
+
+
+
+
+
+//鍖呰鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE packer_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鎮ㄧ殑涓氬姟瀛楁
+ online INTEGER, -- 缃戠粶鐘舵��(0寮傚父锛�1姝e父)
+ qty DOUBLE PRECISION, -- 浜ч噺
+ bad_qty DOUBLE PRECISION, -- 鍓旈櫎浜ч噺
+ xiaohemo_val DOUBLE PRECISION, -- 灏忕洅鑶滄秷鑰�
+ tiaohemo_val DOUBLE PRECISION, -- 鏉$洅鑶滄秷鑰�
+ xiaohezhi_val DOUBLE PRECISION, -- 灏忕洅绾告秷鑰�
+ tiaohezhi_val DOUBLE PRECISION, -- 鏉$洅绾告秷鑰�
+ neichenzhi_val DOUBLE PRECISION, -- 鍐呰‖绾告秷鑰�
+ run_time DOUBLE PRECISION, -- 杩愯鏃堕棿
+ stop_time DOUBLE PRECISION, -- 鍋滄満鏃堕棿
+ stop_times INTEGER, -- 鍋滄満娆℃暟
+ speed INTEGER, -- 杞﹂��
+ run_status INTEGER, -- 杩愯鐘舵��(-1 鏂綉 0鍋滄 1浣庨�熻繍琛� 2姝e父杩愯)
+ ts_qty DOUBLE PRECISION, -- 鎻愬崌鏈轰骇閲�
+ main_qty DOUBLE PRECISION, -- 涓绘満浜ч噺锛堝皬鍖呮満锛�
+ main_bad_qty DOUBLE PRECISION, -- 涓绘満鍓旈櫎閲�
+ tbj_qty DOUBLE PRECISION, -- 閫忓寘鏈轰骇閲�
+ tbj_gd_qty DOUBLE PRECISION, -- 閫忓寘鏈哄墧闄ゅソ鍖�
+ tbj_bad_qty DOUBLE PRECISION, -- 閫忓寘鏈哄墧闄ゅ潖鍖�
+ pbj_qty DOUBLE PRECISION -- 鎺掑寘鏈轰骇閲�
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'packer_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'packer_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓澶嶅悎绱㈠紩锛堟椂闂�+key锛�
+CREATE INDEX idx_packer_time_data_time_key ON packer_time_data (time DESC, key);
+
+-- 鍒涘缓鍙嶅悜澶嶅悎绱㈠紩锛坘ey+鏃堕棿锛�
+CREATE INDEX idx_packer_time_data_key_time ON packer_time_data (key, time DESC);
+
+-- 鍒涘缓杩愯鐘舵�佺浉鍏崇储寮�
+CREATE INDEX idx_packer_run_status_key ON packer_time_data (run_status, key, time DESC);
+
+-- 鍒涘缓缃戠粶鐘舵�佺储寮�
+CREATE INDEX idx_packer_online_key ON packer_time_data (online, key, time DESC);
+
+-- 鍒涘缓杞﹂�熺储寮�
+CREATE INDEX idx_packer_speed_key ON packer_time_data (speed, key, time DESC);
+
+-- 鍒涘缓浜ч噺鐩稿叧绱㈠紩锛堝父鐢ㄧ粺璁℃煡璇級
+CREATE INDEX idx_packer_qty_key ON packer_time_data (qty, key, time DESC);
+
+-- 鍒涘缓鍋滄満鐩稿叧绱㈠紩
+CREATE INDEX idx_packer_stop_key ON packer_time_data (stop_times, key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_packer_time_data_shift ON packer_time_data (shift);
+CREATE INDEX idx_packer_time_data_equ_no ON packer_time_data (equ_no);
+
+
+
+
+
+//瑁呯鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE box_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鎮ㄧ殑涓氬姟瀛楁
+ online INTEGER, -- 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ qty1 DOUBLE PRECISION, -- 1#瑁呭皝绠辨満浜ч噺
+ pbj_qty DOUBLE PRECISION -- 鎺掑寘鏈轰骇閲�
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'box_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'box_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓澶嶅悎绱㈠紩锛堟椂闂�+key锛� - 涓绘煡璇㈡ā寮�
+CREATE INDEX idx_box_time_data_time_key ON box_time_data (time DESC, key);
+
+-- 鍒涘缓鍙嶅悜澶嶅悎绱㈠紩锛坘ey+鏃堕棿锛� - 鎸夎澶囨煡璇�
+CREATE INDEX idx_box_time_data_key_time ON box_time_data (key, time DESC);
+
+-- 鍒涘缓缃戠粶鐘舵�佺储寮�
+CREATE INDEX idx_box_online_key ON box_time_data (online, key, time DESC);
+
+-- 鍒涘缓浜ч噺绱㈠紩锛堝父鐢ㄤ簬缁熻鏌ヨ锛�
+CREATE INDEX idx_box_qty1_key ON box_time_data (qty1, key, time DESC);
+CREATE INDEX idx_box_pbj_qty_key ON box_time_data (pbj_qty, key, time DESC);
+
+-- 鍒涘缓澶嶅悎浜ч噺绱㈠紩锛堝悓鏃舵煡璇袱涓骇閲忓瓧娈碉級
+CREATE INDEX idx_box_qtys_key ON box_time_data (qty1, pbj_qty, key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_box_time_data_shift ON box_time_data (shift);
+CREATE INDEX idx_box_time_data_equ_no ON box_time_data (equ_no);
+
+
+
+
+
+//鎴愬瀷鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE makeup_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鎮ㄧ殑涓氬姟瀛楁
+ online INTEGER, -- 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ qty DOUBLE PRECISION, -- 浜ч噺
+ bad_qty DOUBLE PRECISION, -- 鍓旈櫎浜ч噺
+ panzhi_val DOUBLE PRECISION, -- 鐩樼焊娑堣��
+ run_time DOUBLE PRECISION, -- 杩愯鏃堕棿
+ stop_time DOUBLE PRECISION, -- 鍋滄満鏃堕棿
+ stop_times INTEGER, -- 鍋滄満娆℃暟
+ speed INTEGER -- 杞﹂��
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'makeup_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'makeup_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓涓绘煡璇㈠鍚堢储寮曪紙鏃堕棿+key锛�
+CREATE INDEX idx_makeup_time_data_time_key ON makeup_time_data (time DESC, key);
+
+-- 鍒涘缓鎸夎澶囨煡璇㈠鍚堢储寮曪紙key+鏃堕棿锛�
+CREATE INDEX idx_makeup_time_data_key_time ON makeup_time_data (key, time DESC);
+
+-- 鍒涘缓缃戠粶鐘舵�佺储寮�
+CREATE INDEX idx_makeup_online_key ON makeup_time_data (online, key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_makeup_time_data_shift ON makeup_time_data (shift);
+CREATE INDEX idx_makeup_time_data_equ_no ON makeup_time_data (equ_no);
+
+
+
+
+
+//鍙戝皠鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE trans_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鎮ㄧ殑涓氬姟瀛楁
+ online INTEGER, -- 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+
+ -- 绠¢亾婊ゆ璁℃暟锛�1-10鍙风閬擄級
+ p_qty1 DOUBLE PRECISION, -- 绠¢亾1婊ゆ璁℃暟
+ p_qty2 DOUBLE PRECISION, -- 绠¢亾2婊ゆ璁℃暟
+ p_qty3 DOUBLE PRECISION, -- 绠¢亾3婊ゆ璁℃暟
+ p_qty4 DOUBLE PRECISION, -- 绠¢亾4婊ゆ璁℃暟
+ p_qty5 DOUBLE PRECISION, -- 绠¢亾5婊ゆ璁℃暟
+ p_qty6 DOUBLE PRECISION, -- 绠¢亾6婊ゆ璁℃暟
+ p_qty7 DOUBLE PRECISION, -- 绠¢亾7婊ゆ璁℃暟
+ p_qty8 DOUBLE PRECISION, -- 绠¢亾8婊ゆ璁℃暟
+ p_qty9 DOUBLE PRECISION, -- 绠¢亾9婊ゆ璁℃暟
+ p_qty10 DOUBLE PRECISION, -- 绠¢亾10婊ゆ璁℃暟
+
+ -- 绠¢亾婊ゆ閫熷害锛�1-10鍙风閬擄級
+ speed1 DOUBLE PRECISION, -- 绠¢亾1婊ゆ閫熷害
+ speed2 DOUBLE PRECISION, -- 绠¢亾2婊ゆ閫熷害
+ speed3 DOUBLE PRECISION, -- 绠¢亾3婊ゆ閫熷害
+ speed4 DOUBLE PRECISION, -- 绠¢亾4婊ゆ閫熷害
+ speed5 DOUBLE PRECISION, -- 绠¢亾5婊ゆ閫熷害
+ speed6 DOUBLE PRECISION, -- 绠¢亾6婊ゆ閫熷害
+ speed7 DOUBLE PRECISION, -- 绠¢亾7婊ゆ閫熷害
+ speed8 DOUBLE PRECISION, -- 绠¢亾8婊ゆ閫熷害
+ speed9 DOUBLE PRECISION, -- 绠¢亾9婊ゆ閫熷害
+ speed10 DOUBLE PRECISION, -- 绠¢亾10婊ゆ閫熷害
+
+ -- 鍗哥洏鏈虹浉鍏�
+ xp_state INTEGER, -- 鍗哥洏鏈虹姸鎬�
+ tray_qty1 DOUBLE PRECISION -- 鍗哥洏鏈轰骇閲�
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'trans_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'trans_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓涓绘煡璇㈠鍚堢储寮�
+CREATE INDEX idx_trans_time_data_time_key ON trans_time_data (time DESC, key);
+CREATE INDEX idx_trans_time_data_key_time ON trans_time_data (key, time DESC);
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_trans_time_data_shift ON trans_time_data (shift);
+CREATE INDEX idx_trans_time_data_equ_no ON trans_time_data (equ_no);
+
+-- 鍒涘缓缃戠粶鐘舵�佺储寮�
+CREATE INDEX idx_trans_online_key ON trans_time_data (online, key, time DESC);
+
+-- 鍒涘缓鍗哥洏鏈虹姸鎬佺储寮�
+CREATE INDEX idx_trans_xp_state_key ON trans_time_data (xp_state, key, time DESC);
+
+
+
+
+
+//鎻愬崌鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE hoister_time_data (
+-- 鏃跺簭琛ㄥ繀闇�鐨勫瓧娈�
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鍩虹瀛楁
+ online INTEGER, -- 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ qty DOUBLE PRECISION, -- 浜ч噺锛堟�讳骇閲忥紵锛�
+
+ -- 鎻愬崌鏈虹姸鎬侊紙1-12鍙凤級
+ t_state1 DOUBLE PRECISION, -- 1#鎻愬崌鏈虹姸鎬�
+ t_state2 DOUBLE PRECISION, -- 2#鎻愬崌鏈虹姸鎬�
+ t_state3 DOUBLE PRECISION, -- 3#鎻愬崌鏈虹姸鎬�
+ t_state4 DOUBLE PRECISION, -- 4#鎻愬崌鏈虹姸鎬�
+ t_state5 DOUBLE PRECISION, -- 5#鎻愬崌鏈虹姸鎬�
+ t_state6 DOUBLE PRECISION, -- 6#鎻愬崌鏈虹姸鎬�
+ t_state7 DOUBLE PRECISION, -- 7#鎻愬崌鏈虹姸鎬�
+ t_state8 DOUBLE PRECISION, -- 8#鎻愬崌鏈虹姸鎬�
+ t_state9 DOUBLE PRECISION, -- 9#鎻愬崌鏈虹姸鎬�
+ t_state10 DOUBLE PRECISION, -- 10#鎻愬崌鏈虹姸鎬�
+ t_state11 DOUBLE PRECISION, -- 11#鎻愬崌鏈虹姸鎬�
+ t_state12 DOUBLE PRECISION, -- 12#鎻愬崌鏈虹姸鎬�
+
+ -- 鎺掑寘鏈虹姸鎬侊紙1-4鍙凤級
+ p_state1 DOUBLE PRECISION, -- 1#鎺掑寘鏈虹姸鎬�
+ p_state2 DOUBLE PRECISION, -- 2#鎺掑寘鏈虹姸鎬�
+ p_state3 DOUBLE PRECISION, -- 3#鎺掑寘鏈虹姸鎬�
+ p_state4 DOUBLE PRECISION, -- 4#鎺掑寘鏈虹姸鎬�
+
+ -- 鎻愬崌鏈轰骇閲忥紙1-12鍙凤級
+ t_qty1 DOUBLE PRECISION, -- 1#鎻愬崌鏈轰骇閲�
+ t_qty2 DOUBLE PRECISION, -- 2#鎻愬崌鏈轰骇閲�
+ t_qty3 DOUBLE PRECISION, -- 3#鎻愬崌鏈轰骇閲�
+ t_qty4 DOUBLE PRECISION, -- 4#鎻愬崌鏈轰骇閲�
+ t_qty5 DOUBLE PRECISION, -- 5#鎻愬崌鏈轰骇閲�
+ t_qty6 DOUBLE PRECISION, -- 6#鎻愬崌鏈轰骇閲�
+ t_qty7 DOUBLE PRECISION, -- 7#鎻愬崌鏈轰骇閲�
+ t_qty8 DOUBLE PRECISION, -- 8#鎻愬崌鏈轰骇閲�
+ t_qty9 DOUBLE PRECISION, -- 9#鎻愬崌鏈轰骇閲�
+ t_qty10 DOUBLE PRECISION, -- 10#鎻愬崌鏈轰骇閲�
+ t_qty11 DOUBLE PRECISION, -- 11#鎻愬崌鏈轰骇閲�
+ t_qty12 DOUBLE PRECISION, -- 12#鎻愬崌鏈轰骇閲�
+
+ -- 鎺掑寘鏈轰骇閲忥紙1-4鍙凤級
+ p_qty1 DOUBLE PRECISION, -- 1#鎺掑寘鏈轰骇閲�
+ p_qty2 DOUBLE PRECISION, -- 2#鎺掑寘鏈轰骇閲�
+ p_qty3 DOUBLE PRECISION, -- 3#鎺掑寘鏈轰骇閲�
+ p_qty4 DOUBLE PRECISION -- 4#鎺掑寘鏈轰骇閲�
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'hoister_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'hoister_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓涓绘煡璇㈠鍚堢储寮�
+CREATE INDEX idx_hoister_time_data_time_key ON hoister_time_data (time DESC, key);
+CREATE INDEX idx_hoister_time_data_key_time ON hoister_time_data (key, time DESC);
+
+-- 鍒涘缓缃戠粶鐘舵�佺储寮�
+CREATE INDEX idx_hoister_online_key ON hoister_time_data (online, key, time DESC);
+
+-- 鍒涘缓鎬讳骇閲忕储寮�
+CREATE INDEX idx_hoister_qty_key ON hoister_time_data (qty, key, time DESC);
+
+-- 鍒涘缓鎻愬崌鏈虹姸鎬侀�氱敤绱㈠紩锛堟渶甯哥敤鐨勫嚑涓級
+CREATE INDEX idx_hoister_t_state1_key ON hoister_time_data (t_state1, key, time DESC);
+CREATE INDEX idx_hoister_t_state2_key ON hoister_time_data (t_state2, key, time DESC);
+CREATE INDEX idx_hoister_t_state3_key ON hoister_time_data (t_state3, key, time DESC);
+
+-- 鍒涘缓鎺掑寘鏈虹姸鎬佺储寮�
+CREATE INDEX idx_hoister_p_state1_key ON hoister_time_data (p_state1, key, time DESC);
+CREATE INDEX idx_hoister_p_state2_key ON hoister_time_data (p_state2, key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_hoister_time_data_shift ON hoister_time_data (shift);
+CREATE INDEX idx_hoister_time_data_equ_no ON hoister_time_data (equ_no);
+
+
+
+
+//鍠備笣鏈�
+-- 鍒涘缓涓昏〃
+CREATE TABLE feedmatch_time_data (
+time TIMESTAMPTZ NOT NULL,
+key TEXT NOT NULL,
+shift INTEGER, -- 鐝 (1浣嶆暟瀛�)
+equ_no INTEGER, -- 璁惧鍙� (3浣嶆暟瀛�)
+
+ -- 鏁版嵁鏇存柊鏃堕棿锛堝瓧绗︿覆鏍煎紡锛�
+ dac_up_time TEXT, -- 鏁版嵁鏇存柊鏃堕棿 鏍煎紡锛�'2024-11-29 09:13:43'
+
+ -- 鍠備笣鏈哄搴旂殑鍌ㄤ笣鏌滐紙1#-4#鍠備笣鏈猴紝姣忎釜瀵瑰簲2涓偍涓濇煖锛�- 鏁村瀷
+ fs11 INTEGER, -- 1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ fs12 INTEGER, -- 1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ fs21 INTEGER, -- 2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ fs22 INTEGER, -- 2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ fs31 INTEGER, -- 3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ fs32 INTEGER, -- 3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ fs41 INTEGER, -- 4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ fs42 INTEGER, -- 4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+
+ -- 鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬擄紙1#-12#鏈虹粍锛�- 鏁村瀷
+ pipe01 INTEGER, -- 1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe02 INTEGER, -- 2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe03 INTEGER, -- 3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe04 INTEGER, -- 4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe05 INTEGER, -- 5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe06 INTEGER, -- 6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe07 INTEGER, -- 7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe08 INTEGER, -- 8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe09 INTEGER, -- 9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe10 INTEGER, -- 10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe11 INTEGER, -- 11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ pipe12 INTEGER, -- 12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+
+ -- 鍠備笣鏈虹姸鎬� - 鏁村瀷
+ wsj_state INTEGER -- 鍠備笣鏈虹姸鎬� 1-杩炴帴 0-鏂紑
+);
+
+-- 灏嗚〃杞崲涓鸿秴琛紙鎸夊ぉ鍒嗗尯锛�
+SELECT create_hypertable(
+'feedmatch_time_data',
+'time',
+chunk_time_interval => INTERVAL '1 day'
+);
+
+-- 娣诲姞绌洪棿鍒嗗尯缁村害锛堟寜key鍒嗗尯锛屽垎鎴�8涓垎鍖猴級
+SELECT add_dimension(
+'feedmatch_time_data',
+'key',
+number_partitions => 8
+);
+
+-- 鍒涘缓涓绘煡璇㈠鍚堢储寮�
+CREATE INDEX idx_feedmatch_time_data_time_key ON feedmatch_time_data (time DESC, key);
+CREATE INDEX idx_feedmatch_time_data_key_time ON feedmatch_time_data (key, time DESC);
+
+-- 鐝鍜岃澶囧彿绱㈠紩
+CREATE INDEX idx_feedmatch_time_data_shift ON feedmatch_time_data (shift);
+CREATE INDEX idx_feedmatch_time_data_equ_no ON feedmatch_time_data (equ_no);
+
+//鍚勮〃娣诲姞閫氱敤瀛楁
+ALTER TABLE public.trans_time_data
+ADD COLUMN IF NOT EXISTS create_dept integer,
+ADD COLUMN IF NOT EXISTS create_by bigint,
+ADD COLUMN IF NOT EXISTS create_time timestamp,
+ADD COLUMN IF NOT EXISTS update_by bigint,
+ADD COLUMN IF NOT EXISTS update_time timestamp,
+ADD COLUMN IF NOT EXISTS remark varchar(255);
+
+
+
+// 鍘嗗彶鏁版嵁鏇存柊鑴氭湰锛堟墽琛屼竴娆″嵆鍙級
+-- 鏇存柊 roller_time_data
+UPDATE roller_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 packer_time_data
+UPDATE packer_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 box_time_data
+UPDATE box_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 makeup_time_data
+UPDATE makeup_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 trans_time_data
+UPDATE trans_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 hoister_time_data
+UPDATE hoister_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
+-- 鏇存柊 feedmatch_time_data
+UPDATE feedmatch_time_data SET shift = CAST(SUBSTRING(key FROM 1 FOR 1) AS INTEGER), equ_no = CAST(SUBSTRING(key FROM 2 FOR 3) AS INTEGER) WHERE shift IS NULL;
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplication.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplication.java
new file mode 100755
index 0000000..b4a7afc
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplication.java
@@ -0,0 +1,23 @@
+package com.shlb.timescaledbutils;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+import javax.annotation.PostConstruct;
+import java.util.TimeZone;
+
+@SpringBootApplication
+@MapperScan("com.shlb.timescaledbutils.mapper")
+public class TimescaleDbUtilsApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(TimescaleDbUtilsApplication.class, args);
+ }
+
+ @PostConstruct
+ void started() {
+ TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
+ }
+
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/MybatisPlusConfig.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/MybatisPlusConfig.java
new file mode 100755
index 0000000..3dc34dc
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/MybatisPlusConfig.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.config;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@MapperScan("com.shlb.timescaledbutils.mapper")
+public class MybatisPlusConfig {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/StartupStatusPrinter.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/StartupStatusPrinter.java
new file mode 100755
index 0000000..b8561dd
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/config/StartupStatusPrinter.java
@@ -0,0 +1,53 @@
+package com.shlb.timescaledbutils.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.env.Environment;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.stereotype.Component;
+
+import javax.sql.DataSource;
+import java.sql.Connection;
+
+@Component
+@Slf4j
+public class StartupStatusPrinter implements ApplicationRunner {
+
+ @Autowired
+ private Environment environment;
+
+ @Autowired
+ private DataSource dataSource;
+
+ @Autowired
+ private RedisConnectionFactory redisConnectionFactory;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ String port = environment.getProperty("server.port");
+
+ boolean postgresConnected = false;
+ try (Connection connection = dataSource.getConnection()) {
+ postgresConnected = connection.isValid(1000);
+ } catch (Exception e) {
+ log.error("PostgreSQL 杩炴帴澶辫触: {}", e.getMessage());
+ }
+
+ boolean redisConnected = false;
+ try {
+ String ping = redisConnectionFactory.getConnection().ping();
+ redisConnected = "PONG".equalsIgnoreCase(ping);
+ } catch (Exception e) {
+ log.error("Redis 杩炴帴澶辫触: {}", e.getMessage());
+ }
+
+ System.out.println("\n----------------------------------------------------------");
+ System.out.println("\tApplication is running! Access URLs:");
+ System.out.println("\tLocal: \t\thttp://localhost:" + port);
+ System.out.println("\tPostgreSQL:\t" + (postgresConnected ? "Connected 鉁�" : "Failed 鉂�"));
+ System.out.println("\tRedis:\t\t" + (redisConnected ? "Connected 鉁�" : "Failed 鉂�"));
+ System.out.println("----------------------------------------------------------\n");
+ }
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/constant/AppConstants.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/constant/AppConstants.java
new file mode 100755
index 0000000..06c8636
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/constant/AppConstants.java
@@ -0,0 +1,92 @@
+package com.shlb.timescaledbutils.constant;
+
+import java.util.*;
+
+/**
+ * 绯荤粺甯搁噺绫�
+ */
+public class AppConstants {
+ private AppConstants() {
+ // 闃叉瀹炰緥鍖�
+ }
+
+ /**
+ * 鐝 1銆�2銆�3
+ * 鍗锋帴鏈虹粍 101锝�200
+ * 鍖呰鏈虹粍 201锝�300
+ * 瑁呭皝绠辨満缁� 301锝�400
+ * 鎴愬瀷鏈虹粍 401锝�500
+ * 鍙戝皠鏈虹粍 501锝�600
+ * 鎻愬崌鏈� 601
+ * 鍠備笣鏈� 603
+ */
+
+
+ // 鎵�鏈夎澶囩紪鍙� (涓嶅惈鐝鍓嶇紑)
+ public static final List<String> EQUIPMENT_LIST = Arrays.asList(
+ // 鍗锋帴鏈虹粍
+ "101", "102", "103", "105", "106", "107", "108", "109", "110", "111", "113",
+ // 鍖呰鏈虹粍
+ "201", "202", "203", "205", "206", "207", "208", "209", "210", "211", "213",
+ // 瑁呭皝绠辨満缁�
+ "301", "302", "303", "304", "305",
+ // 鎴愬瀷鏈虹粍
+ "401", "402", "403",
+ // 鍙戝皠鏈虹粍
+ "501", "502", "503",
+ // 鎻愬崌鏈�
+ "601",
+ // 鍠備笣鏈�
+ "603"
+ );
+
+
+ // 璁惧绫诲瀷甯搁噺
+ public static final int TYPE_ROLLING = 1; // 鍗锋帴鏈虹粍
+ public static final int TYPE_PACKAGING = 2; // 鍖呰鏈虹粍
+ public static final int TYPE_SEALING = 3; // 瑁呭皝绠辨満缁�
+ public static final int TYPE_FORMING = 4; // 鎴愬瀷鏈虹粍
+ public static final int TYPE_LAUNCHING = 5; // 鍙戝皠鏈虹粍
+ public static final int TYPE_LIFTING = 6; // 鎻愬崌鏈�
+ public static final int TYPE_FEED = 7; // 鍠備笣鏈�
+
+ // 鐝甯搁噺
+ public static final int SHIFT_MORNING = 1; // 鏃╃彮
+ public static final int SHIFT_MIDDLE = 2; // 涓彮
+ public static final int SHIFT_NIGHT = 3; // 鏅氱彮
+
+ /**
+ * 鑾峰彇璁惧绫诲瀷
+ * @param equipmentCode 璁惧缂栧彿锛屽彲浠ユ槸3浣�(濡�"101")鎴�4浣�(濡�"1101")
+ * @return 1-鍗锋帴鏈虹粍, 2-鍖呰鏈虹粍, 3-瑁呭皝绠辨満缁�, 4-鎴愬瀷鏈虹粍, 5-鍙戝皠鏈虹粍, 6-鎻愬崌鏈�, 7-鍠備笣鏈�, 0-鏃犳晥
+ */
+ public static int getEquipmentType(String equipmentCode) {
+ if (equipmentCode == null || equipmentCode.length() < 3) {
+ return 0;
+ }
+
+ // 鐗规畩璁惧鍒ゆ柇锛�603涓哄杺涓濇満(TYPE=7)锛�601涓烘彁鍗囨満(TYPE=6)
+ // 鏃犺鏄� "603" 杩樻槸 "1603"锛宔ndsWith 閮借兘姝g‘鍒ゆ柇
+ if (equipmentCode.endsWith("603")) {
+ return TYPE_FEED;
+ }
+ if (equipmentCode.endsWith("601")) {
+ return TYPE_LIFTING;
+ }
+
+ // 鑾峰彇绫诲瀷浣嶇殑绱㈠紩
+ // 濡傛灉鏄�4浣嶇紪鐮侊紙濡�1101锛夛紝绫诲瀷浣嶅湪绱㈠紩1
+ // 濡傛灉鏄�3浣嶇紪鐮侊紙濡�101锛夛紝绫诲瀷浣嶅湪绱㈠紩0
+ int typeIndex = equipmentCode.length() == 4 ? 1 : 0;
+
+ if (typeIndex >= equipmentCode.length()) {
+ return 0;
+ }
+
+ char typeChar = equipmentCode.charAt(typeIndex);
+ int type = Character.getNumericValue(typeChar);
+
+ return (type >= 1 && type <= 7) ? type : 0;
+ }
+
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/BoxTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/BoxTimeData.java
new file mode 100755
index 0000000..6a444d2
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/BoxTimeData.java
@@ -0,0 +1,53 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 瑁呯鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("box_time_data")
+public class BoxTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ */
+ private Integer online;
+
+ /**
+ * 1#瑁呭皝绠辨満浜ч噺
+ */
+ private Double qty1;
+
+ /**
+ * 鎺掑寘鏈轰骇閲�
+ */
+ private Double pbjQty;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/FeedmatchTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/FeedmatchTimeData.java
new file mode 100755
index 0000000..f5e65ed
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/FeedmatchTimeData.java
@@ -0,0 +1,148 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鍠備笣鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("feedmatch_time_data")
+public class FeedmatchTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 鏁版嵁鏇存柊鏃堕棿 鏍煎紡锛�'2024-11-29 09:13:43'
+ */
+ private String dacUpTime;
+
+ /**
+ * 1#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ */
+ private String fs11;
+
+ /**
+ * 1#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ */
+ private String fs12;
+
+ /**
+ * 2#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ */
+ private String fs21;
+
+ /**
+ * 2#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ */
+ private String fs22;
+
+ /**
+ * 3#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ */
+ private String fs31;
+
+ /**
+ * 3#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ */
+ private String fs32;
+
+ /**
+ * 4#鍠備笣鏈哄搴旂殑绗竴涓偍涓濇煖
+ */
+ private String fs41;
+
+ /**
+ * 4#鍠備笣鏈哄搴旂殑绗簩涓偍涓濇煖
+ */
+ private String fs42;
+
+ /**
+ * 1#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe01;
+
+ /**
+ * 2#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe02;
+
+ /**
+ * 3#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe03;
+
+ /**
+ * 4#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe04;
+
+ /**
+ * 5#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe05;
+
+ /**
+ * 6#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe06;
+
+ /**
+ * 7#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe07;
+
+ /**
+ * 8#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe08;
+
+ /**
+ * 9#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe09;
+
+ /**
+ * 10#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe10;
+
+ /**
+ * 11#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe11;
+
+ /**
+ * 12#鏈虹粍瀵瑰簲鐨勫杺涓濇満鍜岀閬�
+ */
+ private Integer pipe12;
+
+ /**
+ * 鍠備笣鏈虹姸鎬� 1-杩炴帴 0-鏂紑
+ */
+ private Integer wsjState;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/HoisterTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/HoisterTimeData.java
new file mode 100755
index 0000000..79e0781
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/HoisterTimeData.java
@@ -0,0 +1,208 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鎻愬崌鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("hoister_time_data")
+public class HoisterTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ */
+ private Integer online;
+
+ /**
+ * 浜ч噺锛堟�讳骇閲忥級
+ */
+ private Double qty;
+
+ /**
+ * 1#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState1;
+
+ /**
+ * 2#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState2;
+
+ /**
+ * 3#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState3;
+
+ /**
+ * 4#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState4;
+
+ /**
+ * 5#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState5;
+
+ /**
+ * 6#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState6;
+
+ /**
+ * 7#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState7;
+
+ /**
+ * 8#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState8;
+
+ /**
+ * 9#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState9;
+
+ /**
+ * 10#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState10;
+
+ /**
+ * 11#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState11;
+
+ /**
+ * 12#鎻愬崌鏈虹姸鎬�
+ */
+ private Double tState12;
+
+ /**
+ * 1#鎺掑寘鏈虹姸鎬�
+ */
+ private Double pState1;
+
+ /**
+ * 2#鎺掑寘鏈虹姸鎬�
+ */
+ private Double pState2;
+
+ /**
+ * 3#鎺掑寘鏈虹姸鎬�
+ */
+ private Double pState3;
+
+ /**
+ * 4#鎺掑寘鏈虹姸鎬�
+ */
+ private Double pState4;
+
+ /**
+ * 1#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty1;
+
+ /**
+ * 2#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty2;
+
+ /**
+ * 3#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty3;
+
+ /**
+ * 4#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty4;
+
+ /**
+ * 5#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty5;
+
+ /**
+ * 6#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty6;
+
+ /**
+ * 7#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty7;
+
+ /**
+ * 8#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty8;
+
+ /**
+ * 9#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty9;
+
+ /**
+ * 10#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty10;
+
+ /**
+ * 11#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty11;
+
+ /**
+ * 12#鎻愬崌鏈轰骇閲�
+ */
+ private Double tQty12;
+
+ /**
+ * 1#鎺掑寘鏈轰骇閲�
+ */
+ private Double pQty1;
+
+ /**
+ * 2#鎺掑寘鏈轰骇閲�
+ */
+ private Double pQty2;
+
+ /**
+ * 3#鎺掑寘鏈轰骇閲�
+ */
+ private Double pQty3;
+
+ /**
+ * 4#鎺掑寘鏈轰骇閲�
+ */
+ private Double pQty4;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/MakeupTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/MakeupTimeData.java
new file mode 100755
index 0000000..f8c640e
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/MakeupTimeData.java
@@ -0,0 +1,78 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鎴愬瀷鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("makeup_time_data")
+public class MakeupTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ */
+ private Integer online;
+
+ /**
+ * 浜ч噺
+ */
+ private Double qty;
+
+ /**
+ * 鍓旈櫎浜ч噺
+ */
+ private Double badQty;
+
+ /**
+ * 鐩樼焊娑堣��
+ */
+ private Double panzhiVal;
+
+ /**
+ * 杩愯鏃堕棿
+ */
+ private Double runTime;
+
+ /**
+ * 鍋滄満鏃堕棿
+ */
+ private Double stopTime;
+
+ /**
+ * 鍋滄満娆℃暟
+ */
+ private Integer stopTimes;
+
+ /**
+ * 杞﹂��
+ */
+ private Integer speed;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PackerTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PackerTimeData.java
new file mode 100755
index 0000000..bf42d2a
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PackerTimeData.java
@@ -0,0 +1,138 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鍖呰鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("packer_time_data")
+public class PackerTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵��(0寮傚父锛�1姝e父)
+ */
+ private Integer online;
+
+ /**
+ * 浜ч噺
+ */
+ private Double qty;
+
+ /**
+ * 鍓旈櫎浜ч噺
+ */
+ private Double badQty;
+
+ /**
+ * 灏忕洅鑶滄秷鑰�
+ */
+ private Double xiaohemoVal;
+
+ /**
+ * 鏉$洅鑶滄秷鑰�
+ */
+ private Double tiaohemoVal;
+
+ /**
+ * 灏忕洅绾告秷鑰�
+ */
+ private Double xiaohezhiVal;
+
+ /**
+ * 鏉$洅绾告秷鑰�
+ */
+ private Double tiaohezhiVal;
+
+ /**
+ * 鍐呰‖绾告秷鑰�
+ */
+ private Double neichenzhiVal;
+
+ /**
+ * 杩愯鏃堕棿
+ */
+ private Double runTime;
+
+ /**
+ * 鍋滄満鏃堕棿
+ */
+ private Double stopTime;
+
+ /**
+ * 鍋滄満娆℃暟
+ */
+ private Integer stopTimes;
+
+ /**
+ * 杞﹂��
+ */
+ private Integer speed;
+
+ /**
+ * 杩愯鐘舵��(-1 鏂綉 0鍋滄 1浣庨�熻繍琛� 2姝e父杩愯)
+ */
+ private Integer runStatus;
+
+ /**
+ * 鎻愬崌鏈轰骇閲�
+ */
+ private Double tsQty;
+
+ /**
+ * 涓绘満浜ч噺锛堝皬鍖呮満锛�
+ */
+ private Double mainQty;
+
+ /**
+ * 涓绘満鍓旈櫎閲�
+ */
+ private Double mainBadQty;
+
+ /**
+ * 閫忓寘鏈轰骇閲�
+ */
+ private Double tbjQty;
+
+ /**
+ * 閫忓寘鏈哄墧闄ゅソ鍖�
+ */
+ private Double tbjGdQty;
+
+ /**
+ * 閫忓寘鏈哄墧闄ゅ潖鍖�
+ */
+ private Double tbjBadQty;
+
+ /**
+ * 鎺掑寘鏈轰骇閲�
+ */
+ private Double pbjQty;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PointData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PointData.java
new file mode 100755
index 0000000..3fe31bc
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/PointData.java
@@ -0,0 +1,53 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 鐐逛綅鏃跺簭鏁版嵁瀹炰綋绫�
+ * 瀵瑰簲 TimescaleDB 涓殑 point_time_data 瓒呰〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName(value = "point_time_data", autoResultMap = true)
+public class PointData {
+
+ /**
+ * 鏃堕棿鎴� (TimescaleDB 鐨勬牳蹇冨垎鍖洪敭)
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 鐐逛綅 Key
+ */
+ private String pointKey;
+
+ /**
+ * 鐐逛綅鍊�
+ */
+ private String pointValue;
+
+ /**
+ * 鍙�夌殑鏍囩/鍏冩暟鎹� (JSONB)
+ */
+ @TableField(typeHandler = FastjsonTypeHandler.class)
+ private Map<String, Object> tags;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/RollerTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/RollerTimeData.java
new file mode 100755
index 0000000..67f021b
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/RollerTimeData.java
@@ -0,0 +1,118 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鍗锋帴鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("roller_time_data")
+public class RollerTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵��(0寮傚父 1姝e父)
+ */
+ private Integer online;
+
+ /**
+ * 浜ч噺
+ */
+ private Double qty;
+
+ /**
+ * 鍓旈櫎浜ч噺
+ */
+ private Double badQty;
+
+ /**
+ * 婊ゆ娑堣��
+ */
+ private Double lvbangVal;
+
+ /**
+ * 鍗风儫绾告秷鑰�
+ */
+ private Double juanyanzhiVal;
+
+ /**
+ * 姘存澗绾告秷鑰�
+ */
+ private Double shuisongzhiVal;
+
+ /**
+ * 杩愯鏃堕棿
+ */
+ private Double runTime;
+
+ /**
+ * 鍋滄満鏃堕棿
+ */
+ private Double stopTime;
+
+ /**
+ * 鍋滄満娆℃暟
+ */
+ private Integer stopTimes;
+
+ /**
+ * 杞﹂��
+ */
+ private Integer speed;
+
+ /**
+ * 杩愯鐘舵��(-1鏂綉 0鍋滄 1浣庨�熻繍琛� 2姝e父杩愯)
+ */
+ private Integer runStatus;
+
+ /**
+ * 鍌ㄧ儫璁惧鍌ㄩ噺
+ */
+ private Double cy;
+
+ /**
+ * 鍌ㄧ儫璁惧杞﹂��(1-鍖呰鏈� 6-鍗风儫鏈�)
+ */
+ private Integer cyCs;
+
+ /**
+ * 22-鍗风儫鏈鸿繍琛岀姸鎬� 23-鍖呰鏈鸿繍琛岀姸鎬�
+ */
+ private String cyOnline;
+
+ /**
+ * 鎺ユ敹鏈洪噺
+ */
+ private Double recQty1;
+
+ /**
+ * 鎺ユ敹鏈洪噺2
+ */
+ private Double recQty2;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/TransTimeData.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/TransTimeData.java
new file mode 100755
index 0000000..afa903a
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/entity/TransTimeData.java
@@ -0,0 +1,153 @@
+package com.shlb.timescaledbutils.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.Date;
+
+/**
+ * 鍙戝皠鏈鸿〃
+ */
+@Data
+@Accessors(chain = true)
+@TableName("trans_time_data")
+public class TransTimeData {
+
+ /**
+ * 鏃堕棿鎴�
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date time;
+
+ /**
+ * 璁惧缂栧彿
+ */
+ private String key;
+
+ /**
+ * 缃戠粶鐘舵�� 0寮傚父锛�1姝e父
+ */
+ private Integer online;
+
+ /**
+ * 绠¢亾1婊ゆ璁℃暟
+ */
+ private Double pQty1;
+
+ /**
+ * 绠¢亾2婊ゆ璁℃暟
+ */
+ private Double pQty2;
+
+ /**
+ * 绠¢亾3婊ゆ璁℃暟
+ */
+ private Double pQty3;
+
+ /**
+ * 绠¢亾4婊ゆ璁℃暟
+ */
+ private Double pQty4;
+
+ /**
+ * 绠¢亾5婊ゆ璁℃暟
+ */
+ private Double pQty5;
+
+ /**
+ * 绠¢亾6婊ゆ璁℃暟
+ */
+ private Double pQty6;
+
+ /**
+ * 绠¢亾7婊ゆ璁℃暟
+ */
+ private Double pQty7;
+
+ /**
+ * 绠¢亾8婊ゆ璁℃暟
+ */
+ private Double pQty8;
+
+ /**
+ * 绠¢亾9婊ゆ璁℃暟
+ */
+ private Double pQty9;
+
+ /**
+ * 绠¢亾10婊ゆ璁℃暟
+ */
+ private Double pQty10;
+
+ /**
+ * 绠¢亾1婊ゆ閫熷害
+ */
+ private Double speed1;
+
+ /**
+ * 绠¢亾2婊ゆ閫熷害
+ */
+ private Double speed2;
+
+ /**
+ * 绠¢亾3婊ゆ閫熷害
+ */
+ private Double speed3;
+
+ /**
+ * 绠¢亾4婊ゆ閫熷害
+ */
+ private Double speed4;
+
+ /**
+ * 绠¢亾5婊ゆ閫熷害
+ */
+ private Double speed5;
+
+ /**
+ * 绠¢亾6婊ゆ閫熷害
+ */
+ private Double speed6;
+
+ /**
+ * 绠¢亾7婊ゆ閫熷害
+ */
+ private Double speed7;
+
+ /**
+ * 绠¢亾8婊ゆ閫熷害
+ */
+ private Double speed8;
+
+ /**
+ * 绠¢亾9婊ゆ閫熷害
+ */
+ private Double speed9;
+
+ /**
+ * 绠¢亾10婊ゆ閫熷害
+ */
+ private Double speed10;
+
+ /**
+ * 鍗哥洏鏈虹姸鎬�
+ */
+ private Integer xpState;
+
+ /**
+ * 鍗哥洏鏈轰骇閲�
+ */
+ private Double trayQty1;
+
+ /**
+ * 鐝 (1浣嶆暟瀛�)
+ */
+ private Integer shift;
+
+ /**
+ * 璁惧鍙� (3浣嶆暟瀛�)
+ */
+ private Integer equNo;
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/BoxTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/BoxTimeDataMapper.java
new file mode 100755
index 0000000..f0fe726
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/BoxTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.BoxTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface BoxTimeDataMapper extends BaseMapper<BoxTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/FeedmatchTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/FeedmatchTimeDataMapper.java
new file mode 100755
index 0000000..49cb75a
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/FeedmatchTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.FeedmatchTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface FeedmatchTimeDataMapper extends BaseMapper<FeedmatchTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/HoisterTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/HoisterTimeDataMapper.java
new file mode 100755
index 0000000..2a5a0e2
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/HoisterTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.HoisterTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface HoisterTimeDataMapper extends BaseMapper<HoisterTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/MakeupTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/MakeupTimeDataMapper.java
new file mode 100755
index 0000000..94083c3
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/MakeupTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.MakeupTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MakeupTimeDataMapper extends BaseMapper<MakeupTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PackerTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PackerTimeDataMapper.java
new file mode 100755
index 0000000..beeb3cd
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PackerTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.PackerTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface PackerTimeDataMapper extends BaseMapper<PackerTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PointDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PointDataMapper.java
new file mode 100755
index 0000000..994ba82
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/PointDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.PointData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface PointDataMapper extends BaseMapper<PointData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/RollerTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/RollerTimeDataMapper.java
new file mode 100755
index 0000000..1e3147f
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/RollerTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.RollerTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface RollerTimeDataMapper extends BaseMapper<RollerTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/TransTimeDataMapper.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/TransTimeDataMapper.java
new file mode 100755
index 0000000..c245c3f
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/mapper/TransTimeDataMapper.java
@@ -0,0 +1,9 @@
+package com.shlb.timescaledbutils.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.shlb.timescaledbutils.entity.TransTimeData;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface TransTimeDataMapper extends BaseMapper<TransTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IBoxTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IBoxTimeDataService.java
new file mode 100755
index 0000000..cc880d6
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IBoxTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.BoxTimeData;
+
+public interface IBoxTimeDataService extends IService<BoxTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IFeedmatchTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IFeedmatchTimeDataService.java
new file mode 100755
index 0000000..5f4128c
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IFeedmatchTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.FeedmatchTimeData;
+
+public interface IFeedmatchTimeDataService extends IService<FeedmatchTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IHoisterTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IHoisterTimeDataService.java
new file mode 100755
index 0000000..97a3167
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IHoisterTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.HoisterTimeData;
+
+public interface IHoisterTimeDataService extends IService<HoisterTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IMakeupTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IMakeupTimeDataService.java
new file mode 100755
index 0000000..bfc34cf
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IMakeupTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.MakeupTimeData;
+
+public interface IMakeupTimeDataService extends IService<MakeupTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPackerTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPackerTimeDataService.java
new file mode 100755
index 0000000..94452cf
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPackerTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.PackerTimeData;
+
+public interface IPackerTimeDataService extends IService<PackerTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPointDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPointDataService.java
new file mode 100755
index 0000000..39bb77c
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IPointDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.PointData;
+
+public interface IPointDataService extends IService<PointData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IRollerTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IRollerTimeDataService.java
new file mode 100755
index 0000000..2295d90
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/IRollerTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.RollerTimeData;
+
+public interface IRollerTimeDataService extends IService<RollerTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/ITransTimeDataService.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/ITransTimeDataService.java
new file mode 100755
index 0000000..82f6027
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/ITransTimeDataService.java
@@ -0,0 +1,7 @@
+package com.shlb.timescaledbutils.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.shlb.timescaledbutils.entity.TransTimeData;
+
+public interface ITransTimeDataService extends IService<TransTimeData> {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/BoxTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/BoxTimeDataServiceImpl.java
new file mode 100755
index 0000000..9a9d950
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/BoxTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.BoxTimeData;
+import com.shlb.timescaledbutils.mapper.BoxTimeDataMapper;
+import com.shlb.timescaledbutils.service.IBoxTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class BoxTimeDataServiceImpl extends ServiceImpl<BoxTimeDataMapper, BoxTimeData> implements IBoxTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/FeedmatchTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/FeedmatchTimeDataServiceImpl.java
new file mode 100755
index 0000000..e12346f
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/FeedmatchTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.FeedmatchTimeData;
+import com.shlb.timescaledbutils.mapper.FeedmatchTimeDataMapper;
+import com.shlb.timescaledbutils.service.IFeedmatchTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class FeedmatchTimeDataServiceImpl extends ServiceImpl<FeedmatchTimeDataMapper, FeedmatchTimeData> implements IFeedmatchTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/HoisterTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/HoisterTimeDataServiceImpl.java
new file mode 100755
index 0000000..7ccff9c
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/HoisterTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.HoisterTimeData;
+import com.shlb.timescaledbutils.mapper.HoisterTimeDataMapper;
+import com.shlb.timescaledbutils.service.IHoisterTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class HoisterTimeDataServiceImpl extends ServiceImpl<HoisterTimeDataMapper, HoisterTimeData> implements IHoisterTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/MakeupTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/MakeupTimeDataServiceImpl.java
new file mode 100755
index 0000000..cd4e912
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/MakeupTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.MakeupTimeData;
+import com.shlb.timescaledbutils.mapper.MakeupTimeDataMapper;
+import com.shlb.timescaledbutils.service.IMakeupTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MakeupTimeDataServiceImpl extends ServiceImpl<MakeupTimeDataMapper, MakeupTimeData> implements IMakeupTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PackerTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PackerTimeDataServiceImpl.java
new file mode 100755
index 0000000..6d86033
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PackerTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.PackerTimeData;
+import com.shlb.timescaledbutils.mapper.PackerTimeDataMapper;
+import com.shlb.timescaledbutils.service.IPackerTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PackerTimeDataServiceImpl extends ServiceImpl<PackerTimeDataMapper, PackerTimeData> implements IPackerTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PointDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PointDataServiceImpl.java
new file mode 100755
index 0000000..bca547f
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/PointDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.PointData;
+import com.shlb.timescaledbutils.mapper.PointDataMapper;
+import com.shlb.timescaledbutils.service.IPointDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class PointDataServiceImpl extends ServiceImpl<PointDataMapper, PointData> implements IPointDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/RollerTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/RollerTimeDataServiceImpl.java
new file mode 100755
index 0000000..1973a63
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/RollerTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.RollerTimeData;
+import com.shlb.timescaledbutils.mapper.RollerTimeDataMapper;
+import com.shlb.timescaledbutils.service.IRollerTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class RollerTimeDataServiceImpl extends ServiceImpl<RollerTimeDataMapper, RollerTimeData> implements IRollerTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/TransTimeDataServiceImpl.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/TransTimeDataServiceImpl.java
new file mode 100755
index 0000000..b5d9010
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/service/impl/TransTimeDataServiceImpl.java
@@ -0,0 +1,11 @@
+package com.shlb.timescaledbutils.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.shlb.timescaledbutils.entity.TransTimeData;
+import com.shlb.timescaledbutils.mapper.TransTimeDataMapper;
+import com.shlb.timescaledbutils.service.ITransTimeDataService;
+import org.springframework.stereotype.Service;
+
+@Service
+public class TransTimeDataServiceImpl extends ServiceImpl<TransTimeDataMapper, TransTimeData> implements ITransTimeDataService {
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/task/RedisToPostgresSyncTask.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/task/RedisToPostgresSyncTask.java
new file mode 100755
index 0000000..c19005e
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/task/RedisToPostgresSyncTask.java
@@ -0,0 +1,278 @@
+package com.shlb.timescaledbutils.task;
+
+import com.alibaba.fastjson.JSONObject;
+import com.shlb.timescaledbutils.constant.AppConstants;
+import com.shlb.timescaledbutils.entity.*;
+import com.shlb.timescaledbutils.service.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.core.RedisOperations;
+import org.springframework.data.redis.core.SessionCallback;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Redis 鏁版嵁鍚屾浠诲姟
+ * 瀹氭湡浠� Redis 鑾峰彇璁惧瀹炴椂鏁版嵁骞跺垎娴佸啓鍏ヤ笉鍚� PostgreSQL 琛�
+ */
+@Component
+@Slf4j
+public class RedisToPostgresSyncTask implements ApplicationRunner {
+
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ // 鍚勮澶囧搴旂殑 Service
+ @Autowired
+ private IRollerTimeDataService rollerService;
+ @Autowired
+ private IPackerTimeDataService packerService;
+ @Autowired
+ private IBoxTimeDataService boxService;
+ @Autowired
+ private IMakeupTimeDataService makeupService;
+ @Autowired
+ private ITransTimeDataService transService;
+ @Autowired
+ private IHoisterTimeDataService hoisterService;
+ @Autowired
+ private IFeedmatchTimeDataService feedmatchService;
+
+ @Value("${spring.redis.sync-interval-ms:5000}")
+ private long intervalMs;
+
+ private final ExecutorService executorService = Executors.newSingleThreadExecutor();
+
+ private volatile boolean running = true;
+
+ @Override
+ public void run(ApplicationArguments args) {
+ // 寮哄埗闄愬埗鏈�灏忛棿闅斾负 1000ms
+ if (intervalMs < 1000) {
+ log.warn("閰嶇疆鐨勫悓姝ラ棿闅� {}ms 灏忎簬鏈�灏忛檺鍒� 1000ms锛屽凡鑷姩淇涓� 1000ms", intervalMs);
+ intervalMs = 1000;
+ }
+
+ executorService.submit(this::processSync);
+ log.info("Redis -> PostgreSQL 澶氳〃鍒嗘祦鏁版嵁閲囬泦浠诲姟宸插惎鍔紝閲囬泦闂撮殧: {}ms", intervalMs);
+ }
+
+ private void processSync() {
+ while (running) {
+ try {
+ long startTime = System.currentTimeMillis();
+
+ // 1. 鑾峰彇鐝淇℃伅
+ // Redis Key: "shift", Field: "ID"
+ Object shiftIdObj = stringRedisTemplate.opsForHash().get("shift", "ID");
+ String shiftId = shiftIdObj != null ? shiftIdObj.toString() : null;
+
+ if (shiftId == null || shiftId.isEmpty()) {
+ // 濡傛灉鑾峰彇涓嶅埌鐝锛屽彲鑳芥槸Redis鏆傛椂娌℃暟鎹紝璁板綍error鏃ュ織骞剁瓑寰呬笅涓�娆�
+ log.error("Redis涓湭鎵惧埌鐝淇℃伅 (key='shift', field='id')锛岃烦杩囨湰娆¢噰闆�");
+ sleepRemaining(startTime);
+ continue;
+ }
+
+ // 2. 鏋勯�犳墍鏈夎澶囩殑 Redis Key (鐝 + 璁惧3浣嶇爜)
+ // 渚嬪锛氱彮娆�"2" + 璁惧"101" = "2101"
+ List<String> equipmentKeys = new ArrayList<>(AppConstants.EQUIPMENT_LIST.size());
+ for (String code : AppConstants.EQUIPMENT_LIST) {
+ equipmentKeys.add(shiftId + code);
+ }
+
+ // 3. 鎵归噺鑾峰彇璁惧鏁版嵁 (Pipeline)
+ // 浣跨敤 Pipeline 鍑忓皯缃戠粶 RTT
+ List<Object> results = stringRedisTemplate.executePipelined(new SessionCallback<Object>() {
+ @Override
+ public Object execute(RedisOperations operations) throws DataAccessException {
+ for (String key : equipmentKeys) {
+ operations.opsForHash().entries(key);
+ }
+ return null;
+ }
+ });
+
+ // 灏� results 杞负 Map锛屾柟渚垮悗缁�氳繃 Key 鑾峰彇鍏朵粬璁惧鏁版嵁
+ Map<String, Map<Object, Object>> equipmentDataMap = new HashMap<>();
+ if (results != null) {
+ for (int i = 0; i < results.size(); i++) {
+ Object res = results.get(i);
+ if (res instanceof Map && i < equipmentKeys.size()) {
+ equipmentDataMap.put(equipmentKeys.get(i), (Map<Object, Object>) res);
+ }
+ }
+ }
+
+ // 4. 鏁版嵁鍒嗙被涓庢槧灏�
+ Date now = new Date();
+
+ List<RollerTimeData> rollerList = new ArrayList<>();
+ List<PackerTimeData> packerList = new ArrayList<>();
+ List<BoxTimeData> boxList = new ArrayList<>();
+ List<MakeupTimeData> makeupList = new ArrayList<>();
+ List<TransTimeData> transList = new ArrayList<>();
+ List<HoisterTimeData> hoisterList = new ArrayList<>();
+ List<FeedmatchTimeData> feedmatchList = new ArrayList<>();
+
+ for (int i = 0; i < results.size(); i++) {
+ Object result = results.get(i);
+ // executePipelined 杩斿洖鐨勭粨鏋滀腑锛宧ash entries 杩斿洖鐨勬槸 Map<Object, Object>
+ if (!(result instanceof Map)) {
+ continue;
+ }
+ Map<Object, Object> map = (Map<Object, Object>) result;
+ if (map.isEmpty()) {
+ continue;
+ }
+
+ String fullKey = equipmentKeys.get(i);
+ int type = AppConstants.getEquipmentType(fullKey);
+
+ try {
+ // 瑙f瀽鐝鍜岃澶囧彿
+ Integer shift = null;
+ Integer equNo = null;
+ if (fullKey != null && fullKey.length() >= 4) {
+ try {
+ shift = Integer.parseInt(fullKey.substring(0, 1));
+ equNo = Integer.parseInt(fullKey.substring(1));
+ } catch (NumberFormatException e) {
+ log.warn("瑙f瀽鐝/璁惧鍙峰け璐� Key: {}", fullKey);
+ }
+ }
+
+ // 灏� Map 杞负 JSONObject 浠ヤ究鍒╃敤 fastjson 鐨勭被鍨嬭浆鎹㈠姛鑳�
+ JSONObject json = new JSONObject();
+ for (Map.Entry<Object, Object> entry : map.entrySet()) {
+ json.put(entry.getKey().toString(), entry.getValue());
+ }
+
+ // 鏍规嵁璁惧绫诲瀷杞崲骞舵坊鍔犲埌瀵瑰簲鐨勫垪琛�
+ switch (type) {
+ case AppConstants.TYPE_ROLLING:
+ RollerTimeData roller = json.toJavaObject(RollerTimeData.class);
+ roller.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ rollerList.add(roller);
+ break;
+ case AppConstants.TYPE_PACKAGING:
+ PackerTimeData packer = json.toJavaObject(PackerTimeData.class);
+ packer.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ try {
+ if(json.containsKey("chcQty")){
+ packer.setQty(Double.parseDouble(json.get("chcQty").toString()));
+ }
+ if(json.containsKey("ptchQty")){
+ packer.setMainQty(Double.parseDouble(json.get("ptchQty").toString()));
+ }
+ // 鍖呰鏈洪渶瑕佽幏鍙栨彁鍗囨満鐨勪骇閲忥紝鎻愬崌鏈虹殑key涓� 鏃�1601銆佷腑2601銆佹櫄3601
+ // 閫昏緫锛�1-3鍙峰寘瑁呮満瀵瑰簲tQty1-3锛�4鍙锋棤锛�5-13鍙峰搴攖Qty4-12 (鍗冲彿鏁�-1)
+ if (equNo != null && equNo > 0) {
+ int machineNo = equNo % 100;
+ String targetField = "tQty" + machineNo;;
+// if (machineNo < 4) {
+// targetField = "tQty" + machineNo;
+// } else if (machineNo > 4) {
+// targetField = "tQty" + (machineNo - 1);
+// }
+
+ Map<Object, Object> tsjMap = equipmentDataMap.get(shiftId + "601");
+ if (tsjMap != null) {
+ Object qtyObj = tsjMap.get(targetField);
+ if (qtyObj != null) {
+ packer.setTsQty(Double.parseDouble(qtyObj.toString()));
+ }
+ }
+ }
+ }catch (Exception e){}
+ packerList.add(packer);
+ break;
+ case AppConstants.TYPE_SEALING:
+ BoxTimeData box = json.toJavaObject(BoxTimeData.class);
+ box.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ boxList.add(box);
+ break;
+ case AppConstants.TYPE_FORMING:
+ MakeupTimeData makeup = json.toJavaObject(MakeupTimeData.class);
+ makeup.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ makeupList.add(makeup);
+ break;
+ case AppConstants.TYPE_LAUNCHING:
+ TransTimeData trans = json.toJavaObject(TransTimeData.class);
+ trans.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ transList.add(trans);
+ break;
+ case AppConstants.TYPE_LIFTING:
+ HoisterTimeData hoister = json.toJavaObject(HoisterTimeData.class);
+ hoister.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ hoisterList.add(hoister);
+ break;
+ case AppConstants.TYPE_FEED:
+ FeedmatchTimeData feed = json.toJavaObject(FeedmatchTimeData.class);
+ feed.setTime(now).setKey(fullKey).setShift(shift).setEquNo(equNo);
+ feedmatchList.add(feed);
+ break;
+ default:
+ log.warn("鏈煡鐨勮澶囩被鍨嬶紝Key: {}", fullKey);
+ }
+ } catch (Exception e) {
+ log.error("鏁版嵁杞崲澶辫触 Key: {}", fullKey, e);
+ }
+ }
+
+ // 5. 鎵归噺鍏ュ簱
+ if (!rollerList.isEmpty()) rollerService.saveBatch(rollerList);
+ if (!packerList.isEmpty()) packerService.saveBatch(packerList);
+ if (!boxList.isEmpty()) boxService.saveBatch(boxList);
+ if (!makeupList.isEmpty()) makeupService.saveBatch(makeupList);
+ if (!transList.isEmpty()) transService.saveBatch(transList);
+ if (!hoisterList.isEmpty()) hoisterService.saveBatch(hoisterList);
+ if (!feedmatchList.isEmpty()) feedmatchService.saveBatch(feedmatchList);
+
+ int total = rollerList.size() + packerList.size() + boxList.size() +
+ makeupList.size() + transList.size() + hoisterList.size() + feedmatchList.size();
+
+ if (total > 0) {
+ log.info("閲囬泦瀹屾垚: Shift={}, Total={}, Cost={}ms", shiftId, total, System.currentTimeMillis() - startTime);
+ }
+
+ sleepRemaining(startTime);
+
+ } catch (Exception e) {
+ log.error("鍚屾浠诲姟寮傚父", e);
+ try {
+ TimeUnit.SECONDS.sleep(5);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ private void sleepRemaining(long startTime) {
+ long elapsed = System.currentTimeMillis() - startTime;
+ long sleepTime = intervalMs - elapsed;
+ if (sleepTime > 0) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(sleepTime);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ // 搴旂敤鍏抽棴鏃跺仠姝换鍔�
+ public void stop() {
+ this.running = false;
+ executorService.shutdown();
+ }
+}
diff --git a/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/utils/RedisUtils.java b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/utils/RedisUtils.java
new file mode 100755
index 0000000..23ff341
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/java/com/shlb/timescaledbutils/utils/RedisUtils.java
@@ -0,0 +1,114 @@
+package com.shlb.timescaledbutils.utils;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisUtils {
+
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ /**
+ * 鍐欏叆缂撳瓨
+ *
+ * @param key 閿�
+ * @param value 鍊�
+ * @return true鎴愬姛 false澶辫触
+ */
+ public boolean set(String key, String value) {
+ try {
+ stringRedisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 鍐欏叆缂撳瓨骞惰缃繃鏈熸椂闂�
+ *
+ * @param key 閿�
+ * @param value 鍊�
+ * @param time 鏃堕棿(绉�) time瑕佸ぇ浜�0 濡傛灉time灏忎簬绛変簬0 灏嗚缃棤闄愭湡
+ * @return true鎴愬姛 false澶辫触
+ */
+ public boolean set(String key, String value, long time) {
+ try {
+ if (time > 0) {
+ stringRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 璇诲彇缂撳瓨
+ *
+ * @param key 閿�
+ * @return 鍊�
+ */
+ public String get(String key) {
+ return key == null ? null : stringRedisTemplate.opsForValue().get(key);
+ }
+
+ /**
+ * 鍒犻櫎缂撳瓨
+ *
+ * @param key 閿�
+ */
+ public boolean del(String key) {
+ try {
+ if (key != null && key.length() > 0) {
+ stringRedisTemplate.delete(key);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 鎸囧畾缂撳瓨澶辨晥鏃堕棿
+ *
+ * @param key 閿�
+ * @param time 鏃堕棿(绉�)
+ * @return true鎴愬姛 false澶辫触
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * 鍒ゆ柇key鏄惁瀛樺湪
+ *
+ * @param key 閿�
+ * @return true 瀛樺湪 false涓嶅瓨鍦�
+ */
+ public boolean hasKey(String key) {
+ try {
+ return Boolean.TRUE.equals(stringRedisTemplate.hasKey(key));
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+}
diff --git a/TimescaleDB-Utils/src/main/resources/application.yml b/TimescaleDB-Utils/src/main/resources/application.yml
new file mode 100755
index 0000000..a5996be
--- /dev/null
+++ b/TimescaleDB-Utils/src/main/resources/application.yml
@@ -0,0 +1,37 @@
+spring:
+ datasource:
+ driver-class-name: org.postgresql.Driver
+ # PostgreSQL 椹卞姩涓嶈瘑鍒� serverTimezone锛岄渶瑕佷娇鐢� options=-c timezone=...
+ url: jdbc:postgresql://10.39.186.6:5432/postgres?currentSchema=public&serverTimezone=Asia/Shanghai";
+ username: postgres
+ password: 123456
+ jackson:
+ time-zone: Asia/Shanghai
+ date-format: yyyy-MM-dd HH:mm:ss
+ redis:
+ host: 10.39.186.3
+ port: 6677
+ password:
+ database: 0
+ timeout: 3000
+ queue-key: redis # Redis Hash Key
+ sync-interval-ms: 5000 # 鍚屾闂撮殧锛堟绉掞級锛屾渶灏� 1000
+
+logging:
+ file:
+ name: logs/timescaledb-utils.log
+ logback:
+ rollingpolicy:
+ max-file-size: 10MB
+ max-history: 30
+ level:
+ root: INFO
+
+server:
+ port: 8642
+
+mybatis-plus:
+ mapper-locations: classpath*:mapper/**/*.xml
+ type-aliases-package: com.shlb.timescaledbutils.entity
+# configuration:
+# log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 寮�鍚帶鍒跺彴鎵撳嵃 SQL
diff --git a/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/PostgresDataMonitorTest.java b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/PostgresDataMonitorTest.java
new file mode 100755
index 0000000..66e103a
--- /dev/null
+++ b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/PostgresDataMonitorTest.java
@@ -0,0 +1,80 @@
+package com.shlb.timescaledbutils;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.shlb.timescaledbutils.entity.PointData;
+import com.shlb.timescaledbutils.service.IPointDataService;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+@SpringBootTest
+@Slf4j
+class PostgresDataMonitorTest {
+
+ @Autowired
+ private IPointDataService pointDataService;
+
+ /**
+ * 鐩戞帶鏁版嵁搴撴暟鎹�
+ * 姣�5绉掓煡璇竴娆℃渶鏂扮殑5鏉℃暟鎹拰鎬绘潯鏁�
+ */
+ @Test
+ void monitorData() {
+ log.info("=== 寮�濮嬬洃鎺� PostgreSQL 鏁版嵁鍙樺寲 (鎸� Ctrl+C 鍋滄) ===");
+
+ while (true) {
+ try {
+ // 璁板綍寮�濮嬫椂闂�
+ long start = System.currentTimeMillis();
+
+ // 鏌ヨ鎬绘潯鏁�
+ long count = pointDataService.count();
+
+ // 鏌ヨ鏈�鏂扮殑 5 鏉℃暟鎹� (浣跨敤 LIMIT 5 閬垮厤鍏ㄨ〃鎵弿)
+ LambdaQueryWrapper<PointData> wrapper = new LambdaQueryWrapper<>();
+ wrapper.orderByDesc(PointData::getTime);
+ wrapper.last("LIMIT 5");
+
+ List<PointData> latestData = pointDataService.list(wrapper);
+
+ // 鎵撳嵃缁撴灉
+ log.info("--------------------------------------------------");
+ log.info("褰撳墠鏃堕棿: {}", new java.util.Date());
+ log.info("鏁版嵁搴撴�绘潯鏁�: {}", count);
+ log.info("鏈�鏂� 5 鏉℃暟鎹�:");
+ if (latestData.isEmpty()) {
+ log.info(" (鏆傛棤鏁版嵁)");
+ } else {
+ for (PointData data : latestData) {
+ log.info(" {}", data);
+ }
+ }
+ log.info("--------------------------------------------------");
+
+ // 璁$畻浼戠湢鏃堕棿
+ long elapsed = System.currentTimeMillis() - start;
+ long sleepTime = 5000 - elapsed;
+ if (sleepTime > 0) {
+ TimeUnit.MILLISECONDS.sleep(sleepTime);
+ }
+
+ } catch (InterruptedException e) {
+ log.warn("鐩戞帶浠诲姟琚腑鏂�");
+ Thread.currentThread().interrupt();
+ break;
+ } catch (Exception e) {
+ log.error("鏌ヨ鏁版嵁寮傚父", e);
+ try {
+ TimeUnit.SECONDS.sleep(5);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/RollerTimeDataTest.java b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/RollerTimeDataTest.java
new file mode 100755
index 0000000..50ff48e
--- /dev/null
+++ b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/RollerTimeDataTest.java
@@ -0,0 +1,29 @@
+package com.shlb.timescaledbutils;
+
+import com.shlb.timescaledbutils.entity.RollerTimeData;
+import com.shlb.timescaledbutils.service.IRollerTimeDataService;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+import java.util.List;
+
+@SpringBootTest
+public class RollerTimeDataTest {
+
+ @Autowired
+ private IRollerTimeDataService rollerTimeDataService;
+
+ @Test
+ public void testQueryAll() {
+ long startTime = System.currentTimeMillis();
+
+ List<RollerTimeData> list = rollerTimeDataService.list();
+
+ long endTime = System.currentTimeMillis();
+ long duration = endTime - startTime;
+
+ System.out.println("鏌ヨ鑰楁椂: " + duration + " ms");
+ System.out.println("鏌ヨ鍒扮殑璁板綍鏁�: " + (list != null ? list.size() : 0));
+ }
+}
diff --git a/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplicationTests.java b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplicationTests.java
new file mode 100755
index 0000000..1bc21fd
--- /dev/null
+++ b/TimescaleDB-Utils/src/test/java/com/shlb/timescaledbutils/TimescaleDbUtilsApplicationTests.java
@@ -0,0 +1,40 @@
+package com.shlb.timescaledbutils;
+
+import com.shlb.timescaledbutils.utils.RedisUtils;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class TimescaleDbUtilsApplicationTests {
+
+ @Autowired
+ private RedisUtils redisUtils;
+
+ @Test
+ void contextLoads() {
+ }
+
+ @Test
+ void testRedis() {
+ String key = "testKey";
+ String value = "hello redis";
+
+ // 娴嬭瘯鍐欏叆
+ boolean set = redisUtils.set(key, value);
+ Assertions.assertTrue(set, "Redis鍐欏叆澶辫触");
+
+ // 娴嬭瘯璇诲彇
+ String result = redisUtils.get(key);
+ Assertions.assertEquals(value, result, "Redis璇诲彇鍊间笉鍖归厤");
+
+ // 娴嬭瘯鍒犻櫎
+ boolean del = redisUtils.del(key);
+ Assertions.assertTrue(del, "Redis鍒犻櫎澶辫触");
+
+ // 楠岃瘉鍒犻櫎
+ Assertions.assertFalse(redisUtils.hasKey(key), "Redis key搴斿凡琚垹闄�");
+ }
+
+}
diff --git a/ruoyi-plus-soybean/src/service/api/qm/batch.ts b/ruoyi-plus-soybean/src/service/api/qm/batch.ts
new file mode 100644
index 0000000..461638f
--- /dev/null
+++ b/ruoyi-plus-soybean/src/service/api/qm/batch.ts
@@ -0,0 +1,35 @@
+import { request } from '@/service/request';
+
+/** 鑾峰彇妫�楠屾壒娆″垪琛� */
+export function fetchGetBatchList (params?: Api.Qm.BatchSearchParams) {
+ return request<Api.Qm.BatchList>({
+ url: '/qm/batch/list',
+ method: 'get',
+ params
+ });
+}
+/** 鏂板妫�楠屾壒娆� */
+export function fetchCreateBatch (data: Api.Qm.BatchOperateParams) {
+ return request<boolean>({
+ url: '/qm/batch',
+ method: 'post',
+ data
+ });
+}
+
+/** 淇敼妫�楠屾壒娆� */
+export function fetchUpdateBatch (data: Api.Qm.BatchOperateParams) {
+ return request<boolean>({
+ url: '/qm/batch',
+ method: 'put',
+ data
+ });
+}
+
+/** 鎵归噺鍒犻櫎妫�楠屾壒娆� */
+export function fetchBatchDeleteBatch (ids: CommonType.IdType[]) {
+ return request<boolean>({
+ url: `/qm/batch/${ids.join(',')}`,
+ method: 'delete'
+ });
+}
diff --git a/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts b/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts
new file mode 100644
index 0000000..8998bcc
--- /dev/null
+++ b/ruoyi-plus-soybean/src/typings/api/qm.batch.api.d.ts
@@ -0,0 +1,185 @@
+/**
+ * Namespace Api
+ *
+ * All backend api type
+ */
+declare namespace Api {
+ /**
+ * namespace Qm
+ *
+ * backend api module: "Qm"
+ */
+ namespace Qm {
+ /** batch */
+ type Batch = Common.CommonRecord<{
+ /** 缂栫爜 */
+ id: CommonType.IdType;
+ /** 鎵规浠g爜 */
+ batchCode: string;
+ /** 鎵规鍚嶇О */
+ batchName: string;
+ /** A-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂� */
+ typ: string;
+ /** 鏈哄彴浠g爜 */
+ eqpCode: string;
+ /** 鐗屽彿 */
+ matCode: string;
+ /** 鍒ゅ畾渚濇嵁浠g爜 */
+ judgeCode: string;
+ /** 鎵规鐢熸垚鏃ユ湡 */
+ batchDate: string;
+ /** 浣跨敤鏍囧織 */
+ isflag: string;
+ /** 鍚敤鏍囧織 */
+ enabled: string;
+ /** 鍒拌揣鎬婚噺 */
+ totalNum: number;
+ /** 缁煎悎鍒ゅ畾 */
+ results: string;
+ /** 鎵瑰噯浜� */
+ approver: string;
+ /** 瀹℃牳浜� */
+ auditor: string;
+ /** 鍒涘缓浜� */
+ creater: string;
+ /** 鍒惰〃鏃ユ湡 */
+ tabDate: string;
+ /** 鐗堟湰鍚嶇О */
+ verName: string;
+ /** 鐗堟湰缂栧彿 */
+ verCode: string;
+ /** 淇濆瓨鏈� */
+ archDate: string;
+ /** 0-鏈笂浼爉es,1-宸蹭笂浼�, 3-浠嶮ES涓嬭浇 */
+ flag: string;
+ /** 涓婁紶MES鏃堕棿 */
+ toMesDate: string;
+ /** 浠嶮ES鏃堕棿涓嬭浇 */
+ fromMesDate: string;
+ /** 鍒犻櫎鏍囧織 */
+ deleted: number;
+ /** 鎵规鎻忚堪 */
+ batchDes: string;
+ /** 绫诲埆 0锛氭垚鍝� 1锛氳緟鏉� */
+ category: string;
+ /** 鍗峰埗宸ュ彿 */
+ makeno: string;
+ /** 鐝鏈哄彿 */
+ shifteqpno: string;
+ /** 瑁呯鍙� */
+ boxno: string;
+ /** 鐖舵壒娆″彿 */
+ pid: CommonType.IdType;
+ /** 澶嶆牳浜� */
+ reviewer: string;
+ /** 澶嶆娆℃暟 */
+ rvcount: number;
+ /** 鎵规鐘舵�� */
+ state: string;
+ /** 澶嶆牳鏃ユ湡 */
+ reviewTime: string;
+ /** 瀹℃牳鏃ユ湡 */
+ auditTime: string;
+ /** 瑙勬牸 */
+ spec: string;
+ /** 鎵瑰噯鏃堕棿 */
+ approveTime: string;
+ /** 鍒拌揣鍗曚綅 */
+ unit: string;
+ /** 鍒拌揣鏃ユ湡 */
+ arrivalTime: string;
+ /** 瀛樻斁鍦扮偣 */
+ storagePlace: string;
+ /** 妫�楠屽憳 */
+ checker: string;
+ /** 鎺ュ崟鏃ユ湡 */
+ receiveTime: string;
+ /** 鎶ユ鏃ユ湡 */
+ inspTime: string;
+ /** 浠撳簱淇濈鍛� */
+ storer: string;
+ /** 鏄惁楠岃瘉 */
+ isverify: string;
+ /** 鏄惁妫�楠� */
+ ischk: string;
+ /** 澶囩敤1 */
+ bak1: string;
+ /** 澶囩敤2 */
+ bak2: string;
+ }>;
+
+ /** batch search params */
+ type BatchSearchParams = CommonType.RecordNullable<
+ Pick<
+ Api.Qm.Batch,
+ | 'batchCode'
+ | 'typ'
+ | 'eqpCode'
+ | 'matCode'
+ | 'batchDate'
+ | 'flag'
+ | 'deleted'
+ | 'category'
+ | 'state'
+ > &
+ Api.Common.CommonSearchParams
+ >;
+
+ /** batch operate params */
+ type BatchOperateParams = CommonType.RecordNullable<
+ Pick<
+ Api.Qm.Batch,
+ | 'id'
+ | 'batchCode'
+ | 'batchName'
+ | 'typ'
+ | 'eqpCode'
+ | 'matCode'
+ | 'judgeCode'
+ | 'batchDate'
+ | 'isflag'
+ | 'enabled'
+ | 'totalNum'
+ | 'results'
+ | 'approver'
+ | 'auditor'
+ | 'creater'
+ | 'tabDate'
+ | 'verName'
+ | 'verCode'
+ | 'archDate'
+ | 'flag'
+ | 'toMesDate'
+ | 'fromMesDate'
+ | 'deleted'
+ | 'batchDes'
+ | 'category'
+ | 'makeno'
+ | 'shifteqpno'
+ | 'boxno'
+ | 'pid'
+ | 'reviewer'
+ | 'rvcount'
+ | 'state'
+ | 'reviewTime'
+ | 'auditTime'
+ | 'spec'
+ | 'approveTime'
+ | 'unit'
+ | 'arrivalTime'
+ | 'storagePlace'
+ | 'checker'
+ | 'receiveTime'
+ | 'inspTime'
+ | 'storer'
+ | 'isverify'
+ | 'ischk'
+ | 'bak1'
+ | 'bak2'
+ >
+ >;
+
+ /** batch list */
+ type BatchList = Api.Common.PaginatingQueryRecord<Batch>;
+ }
+}
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/index.vue b/ruoyi-plus-soybean/src/views/qm/batch/index.vue
new file mode 100644
index 0000000..06ebbff
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/batch/index.vue
@@ -0,0 +1,474 @@
+<script setup lang="tsx">
+import { ref } from 'vue';
+import { NDivider } from 'naive-ui';
+import { fetchBatchDeleteBatch, fetchGetBatchList } from '@/service/api/qm/batch';
+import { useAppStore } from '@/store/modules/app';
+import { useAuth } from '@/hooks/business/auth';
+import { useDownload } from '@/hooks/business/download';
+import { defaultTransform, useNaivePaginatedTable, useTableOperate } from '@/hooks/common/table';
+import { $t } from '@/locales';
+import ButtonIcon from '@/components/custom/button-icon.vue';
+import BatchOperateDrawer from './modules/batch-operate-drawer.vue';
+import BatchSearch from './modules/batch-search.vue';
+
+defineOptions({
+ name: 'BatchList'
+});
+
+
+const appStore = useAppStore();
+const { download } = useDownload();
+const { hasAuth } = useAuth();
+
+// 绫诲瀷/鍙嶉MES/绫诲埆鐨� value->label 鏄犲皠锛堢敤浜庤〃鏍兼樉绀猴級
+const TYP_MAP: Record<string, string> = { A: '鍒朵笣', B: '鎴愬瀷', C: '鍗峰寘', D: '灏佺', E: '绯栭鏂�' };
+const FLAG_MAP: Record<string, string> = { '0': '鏈笂浼爉es', '1': '宸蹭笂浼�', '3': '浠嶮ES涓嬭浇' };
+const CATEGORY_MAP: Record<string, string> = { '0': '鎴愬搧', '1': '杈呮潗' };
+
+const searchParams = ref<Api.Qm.BatchSearchParams>({
+ pageNum: 1,
+ pageSize: 10,
+ batchCode: null,
+ typ: null,
+ eqpCode: null,
+ matCode: null,
+ batchDate: null,
+ flag: null,
+ toMesDate: null,
+ fromMesDate: null,
+ deleted: null,
+ category: null,
+ state: null,
+ params: {}
+});
+
+const { columns, columnChecks, data, getData, getDataByPage, loading, mobilePagination, scrollX } =
+ useNaivePaginatedTable({
+ api: () => fetchGetBatchList(searchParams.value),
+ transform: response => defaultTransform(response),
+ onPaginationParamsChange: params => {
+ searchParams.value.pageNum = params.page;
+ searchParams.value.pageSize = params.pageSize;
+ },
+ columns: () => [
+ {
+ type: 'selection',
+ align: 'center',
+ width: 48
+ },
+ {
+ key: 'index',
+ title: $t('common.index'),
+ align: 'center',
+ width: 64,
+ render: (_, index) => index + 1
+ },
+ {
+ key: 'id',
+ title: '缂栫爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'batchCode',
+ title: '鎵规浠g爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'batchName',
+ title: '鎵规鍚嶇О',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'typ',
+ title: '绫诲瀷',
+ align: 'center',
+ minWidth: 120,
+ render: row => TYP_MAP[row.typ] ?? row.typ
+ },
+ {
+ key: 'eqpCode',
+ title: '鏈哄彴浠g爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'matCode',
+ title: '鐗屽彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'judgeCode',
+ title: '鍒ゅ畾渚濇嵁浠g爜',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'batchDate',
+ title: '鎵规鐢熸垚鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'isflag',
+ title: '浣跨敤鏍囧織',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'enabled',
+ title: '鍚敤鏍囧織',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'totalNum',
+ title: '鍒拌揣鎬婚噺',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'results',
+ title: '缁煎悎鍒ゅ畾',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'approver',
+ title: '鎵瑰噯浜�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'auditor',
+ title: '瀹℃牳浜�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'creater',
+ title: '鍒涘缓浜�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'tabDate',
+ title: '鍒惰〃鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'verName',
+ title: '鐗堟湰鍚嶇О',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'verCode',
+ title: '鐗堟湰缂栧彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'archDate',
+ title: '淇濆瓨鏈�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'flag',
+ title: '鍙嶉MES',
+ align: 'center',
+ minWidth: 120,
+ render: row => FLAG_MAP[String(row.flag)] ?? row.flag
+ },
+ {
+ key: 'toMesDate',
+ title: '涓婁紶MES鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'fromMesDate',
+ title: '浠嶮ES鏃堕棿涓嬭浇',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'deleted',
+ title: '鍒犻櫎鏍囧織',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'batchDes',
+ title: '鎵规鎻忚堪',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'category',
+ title: '绫诲埆',
+ align: 'center',
+ minWidth: 120,
+ render: row => CATEGORY_MAP[String(row.category)] ?? row.category
+ },
+ {
+ key: 'makeno',
+ title: '鍗峰埗宸ュ彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'shifteqpno',
+ title: '鐝鏈哄彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'boxno',
+ title: '瑁呯鍙�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'pid',
+ title: '鐖舵壒娆″彿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'reviewer',
+ title: '澶嶆牳浜�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'rvcount',
+ title: '澶嶆娆℃暟',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'state',
+ title: '鎵规鐘舵��',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'reviewTime',
+ title: '澶嶆牳鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'auditTime',
+ title: '瀹℃牳鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'spec',
+ title: '瑙勬牸',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'approveTime',
+ title: '鎵瑰噯鏃堕棿',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'unit',
+ title: '鍒拌揣鍗曚綅',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'arrivalTime',
+ title: '鍒拌揣鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'storagePlace',
+ title: '瀛樻斁鍦扮偣',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'checker',
+ title: '妫�楠屽憳',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'receiveTime',
+ title: '鎺ュ崟鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'inspTime',
+ title: '鎶ユ鏃ユ湡',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'storer',
+ title: '浠撳簱淇濈鍛�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'isverify',
+ title: '鏄惁楠岃瘉',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'ischk',
+ title: '鏄惁妫�楠�',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'bak1',
+ title: '澶囩敤1',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'bak2',
+ title: '澶囩敤2',
+ align: 'center',
+ minWidth: 120
+ },
+ {
+ key: 'operate',
+ title: $t('common.operate'),
+ align: 'center',
+ width: 130,
+ render: row => {
+ const divider = () => {
+ if (!hasAuth('qm:batch:edit') || !hasAuth('qm:batch:remove')) {
+ return null;
+ }
+ return <NDivider vertical />;
+ };
+
+ const editBtn = () => {
+ if (!hasAuth('qm:batch:edit')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="primary"
+ icon="material-symbols:drive-file-rename-outline-outline"
+ tooltipContent={$t('common.edit')}
+ onClick={() => edit(row.id)}
+ />
+ );
+ };
+
+ const deleteBtn = () => {
+ if (!hasAuth('qm:batch:remove')) {
+ return null;
+ }
+ return (
+ <ButtonIcon
+ text
+ type="error"
+ icon="material-symbols:delete-outline"
+ tooltipContent={$t('common.delete')}
+ popconfirmContent={$t('common.confirmDelete')}
+ onPositiveClick={() => handleDelete(row.id)}
+ />
+ );
+ };
+
+ return (
+ <div class="flex-center gap-8px">
+ {editBtn()}
+ {divider()}
+ {deleteBtn()}
+ </div>
+ );
+ }
+ }
+ ]
+});
+
+const { drawerVisible, operateType, editingData, handleAdd, handleEdit, checkedRowKeys, onBatchDeleted, onDeleted } =
+ useTableOperate(data, 'id', getData);
+
+async function handleBatchDelete() {
+ // request
+ const { error } = await fetchBatchDeleteBatch(checkedRowKeys.value);
+ if (error) return;
+ onBatchDeleted();
+}
+
+async function handleDelete(id: CommonType.IdType) {
+ // request
+ const { error } = await fetchBatchDeleteBatch([id]);
+ if (error) return;
+ onDeleted();
+}
+
+function edit(id: CommonType.IdType) {
+ handleEdit(id);
+}
+
+function handleExport() {
+ download('/qm/batch/export', searchParams.value, `妫�楠屾壒娆${new Date().getTime()}.xlsx`);
+}
+</script>
+
+<template>
+ <div class="min-h-500px flex-col-stretch gap-16px overflow-hidden lt-sm:overflow-auto">
+ <BatchSearch v-model:model="searchParams" @search="getDataByPage" />
+ <NCard title="妫�楠屾壒娆″垪琛�" :bordered="false" size="small" class="card-wrapper sm:flex-1-hidden">
+ <template #header-extra>
+ <TableHeaderOperation
+ v-model:columns="columnChecks"
+ :disabled-delete="checkedRowKeys.length === 0"
+ :loading="loading"
+ :show-add="hasAuth('qm:batch:add')"
+ :show-delete="hasAuth('qm:batch:remove')"
+ :show-export="hasAuth('qm:batch:export')"
+ @add="handleAdd"
+ @delete="handleBatchDelete"
+ @export="handleExport"
+ @refresh="getData"
+ />
+ </template>
+ <NDataTable
+ v-model:checked-row-keys="checkedRowKeys"
+ :columns="columns"
+ :data="data"
+ size="small"
+ :flex-height="!appStore.isMobile"
+ :scroll-x="scrollX"
+ :loading="loading"
+ remote
+ :row-key="row => row.id"
+ :pagination="mobilePagination"
+ class="sm:h-full"
+ />
+ <BatchOperateDrawer
+ v-model:visible="drawerVisible"
+ :operate-type="operateType"
+ :row-data="editingData"
+ @submitted="getDataByPage"
+ />
+ </NCard>
+ </div>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue
new file mode 100644
index 0000000..501cb94
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-operate-drawer.vue
@@ -0,0 +1,373 @@
+<script setup lang="ts">
+import { computed, ref, watch } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { fetchCreateBatch, fetchUpdateBatch } from '@/service/api/qm/batch';
+import { useFormRules, useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'BatchOperateDrawer'
+});
+
+interface Props {
+ /** the type of operation */
+ operateType: NaiveUI.TableOperateType;
+ /** the edit row data */
+ rowData?: Api.Qm.Batch | null;
+}
+
+const props = defineProps<Props>();
+
+interface Emits {
+ (e: 'submitted'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const visible = defineModel<boolean>('visible', {
+ default: false
+});
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+const { createRequiredRule } = useFormRules();
+
+// 绫诲瀷閫夐」锛欰-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
+const typOptions = [
+ { label: '鍒朵笣', value: 'A' },
+ { label: '鎴愬瀷', value: 'B' },
+ { label: '鍗峰寘', value: 'C' },
+ { label: '灏佺', value: 'D' },
+ { label: '绯栭鏂�', value: 'E' }
+];
+
+// 鍙嶉MES閫夐」锛�0-鏈笂浼爉es 1-宸蹭笂浼� 3-浠嶮ES涓嬭浇
+const flagOptions = [
+ { label: '鏈笂浼爉es', value: '0' },
+ { label: '宸蹭笂浼�', value: '1' },
+ { label: '浠嶮ES涓嬭浇', value: '3' }
+];
+
+// 绫诲埆閫夐」锛�0-鎴愬搧 1-杈呮潗
+const categoryOptions = [
+ { label: '鎴愬搧', value: '0' },
+ { label: '杈呮潗', value: '1' }
+];
+
+const title = computed(() => {
+ const titles: Record<NaiveUI.TableOperateType, string> = {
+ add: '鏂板妫�楠屾壒娆�',
+ edit: '缂栬緫妫�楠屾壒娆�'
+ };
+ return titles[props.operateType];
+});
+
+type Model = Api.Qm.BatchOperateParams;
+
+const model = ref<Model>(createDefaultModel());
+
+function createDefaultModel(): Model {
+ return {
+ id: '',
+ batchCode: '',
+ batchName: '',
+ typ: '',
+ eqpCode: '',
+ matCode: '',
+ judgeCode: '',
+ batchDate: null,
+ isflag: '',
+ enabled: '',
+ totalNum: null,
+ results: '',
+ approver: '',
+ auditor: '',
+ creater: '',
+ tabDate: null,
+ verName: '',
+ verCode: '',
+ archDate: '',
+ flag: '',
+ toMesDate: null,
+ fromMesDate: null,
+ deleted: null,
+ batchDes: '',
+ category: '',
+ makeno: '',
+ shifteqpno: '',
+ boxno: '',
+ pid: '',
+ reviewer: '',
+ rvcount: null,
+ state: '',
+ reviewTime: null,
+ auditTime: null,
+ spec: '',
+ approveTime: null,
+ unit: '',
+ arrivalTime: null,
+ storagePlace: '',
+ checker: '',
+ receiveTime: null,
+ inspTime: null,
+ storer: '',
+ isverify: '',
+ ischk: '',
+ bak1: '',
+ bak2: ''
+ };
+}
+
+type RuleKey = Extract<
+ keyof Model,
+ | 'id'
+>;
+
+const rules: Record<RuleKey, App.Global.FormRule> = {
+ id: createRequiredRule('缂栫爜涓嶈兘涓虹┖'),
+};
+
+function handleUpdateModelWhenEdit() {
+ model.value = createDefaultModel();
+
+ if (props.operateType === 'edit' && props.rowData) {
+ Object.assign(model.value, jsonClone(props.rowData));
+ }
+}
+
+function closeDrawer() {
+ visible.value = false;
+}
+
+async function handleSubmit() {
+ await validate();
+
+ const { id, batchCode, batchName, typ, eqpCode, matCode, judgeCode, batchDate, isflag, enabled, totalNum, results, approver, auditor, creater, tabDate, verName, verCode, archDate, flag, toMesDate, fromMesDate, deleted, batchDes, category, makeno, shifteqpno, boxno, pid, reviewer, rvcount, state, reviewTime, auditTime, spec, approveTime, unit, arrivalTime, storagePlace, checker, receiveTime, inspTime, storer, isverify, ischk, bak1, bak2 } = model.value;
+
+ // request
+ if (props.operateType === 'add') {
+ const { error } = await fetchCreateBatch({ batchCode, batchName, typ, eqpCode, matCode, judgeCode, batchDate, isflag, enabled, totalNum, results, approver, auditor, creater, tabDate, verName, verCode, archDate, flag, toMesDate, fromMesDate, deleted, batchDes, category, makeno, shifteqpno, boxno, pid, reviewer, rvcount, state, reviewTime, auditTime, spec, approveTime, unit, arrivalTime, storagePlace, checker, receiveTime, inspTime, storer, isverify, ischk, bak1, bak2 });
+ if (error) return;
+ }
+
+ if (props.operateType === 'edit') {
+ const { error } = await fetchUpdateBatch({ id, batchCode, batchName, typ, eqpCode, matCode, judgeCode, batchDate, isflag, enabled, totalNum, results, approver, auditor, creater, tabDate, verName, verCode, archDate, flag, toMesDate, fromMesDate, deleted, batchDes, category, makeno, shifteqpno, boxno, pid, reviewer, rvcount, state, reviewTime, auditTime, spec, approveTime, unit, arrivalTime, storagePlace, checker, receiveTime, inspTime, storer, isverify, ischk, bak1, bak2 });
+ if (error) return;
+ }
+
+ window.$message?.success($t('common.updateSuccess'));
+ closeDrawer();
+ emit('submitted');
+}
+
+watch(visible, () => {
+ if (visible.value) {
+ handleUpdateModelWhenEdit();
+ restoreValidation();
+ }
+});
+</script>
+
+<template>
+ <NDrawer v-model:show="visible" :title="title" display-directive="show" :width="800" class="max-w-90%">
+ <NDrawerContent :title="title" :native-scrollbar="false" closable>
+ <NForm ref="formRef" :model="model" :rules="rules">
+ <NFormItem label="鎵规浠g爜" path="batchCode">
+ <NInput v-model:value="model.batchCode" placeholder="璇疯緭鍏ユ壒娆′唬鐮�" />
+ </NFormItem>
+ <NFormItem label="鎵规鍚嶇О" path="batchName">
+ <NInput v-model:value="model.batchName" placeholder="璇疯緭鍏ユ壒娆″悕绉�" />
+ </NFormItem>
+ <NFormItem label="绫诲瀷" path="typ">
+ <NSelect v-model:value="model.typ" :options="typOptions" placeholder="璇烽�夋嫨绫诲瀷" clearable />
+ </NFormItem>
+ <NFormItem label="鏈哄彴浠g爜" path="eqpCode">
+ <NInput v-model:value="model.eqpCode" placeholder="璇疯緭鍏ユ満鍙颁唬鐮�" />
+ </NFormItem>
+ <NFormItem label="鐗屽彿" path="matCode">
+ <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墝鍙�" />
+ </NFormItem>
+ <NFormItem label="鍒ゅ畾渚濇嵁浠g爜" path="judgeCode">
+ <NInput v-model:value="model.judgeCode" placeholder="璇疯緭鍏ュ垽瀹氫緷鎹唬鐮�" />
+ </NFormItem>
+ <NFormItem label="鎵规鐢熸垚鏃ユ湡" path="batchDate">
+ <NDatePicker
+ v-model:formatted-value="model.batchDate"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="浣跨敤鏍囧織" path="isflag">
+ <NInput v-model:value="model.isflag" placeholder="璇疯緭鍏ヤ娇鐢ㄦ爣蹇�" />
+ </NFormItem>
+ <NFormItem label="鍚敤鏍囧織" path="enabled">
+ <NInput v-model:value="model.enabled" placeholder="璇疯緭鍏ュ惎鐢ㄦ爣蹇�" />
+ </NFormItem>
+ <NFormItem label="鍒拌揣鎬婚噺" path="totalNum">
+ <NInput v-model:value="model.totalNum" placeholder="璇疯緭鍏ュ埌璐ф�婚噺" />
+ </NFormItem>
+ <NFormItem label="缁煎悎鍒ゅ畾" path="results">
+ <NInput v-model:value="model.results" placeholder="璇疯緭鍏ョ患鍚堝垽瀹�" />
+ </NFormItem>
+ <NFormItem label="鎵瑰噯浜�" path="approver">
+ <NInput v-model:value="model.approver" placeholder="璇疯緭鍏ユ壒鍑嗕汉" />
+ </NFormItem>
+ <NFormItem label="瀹℃牳浜�" path="auditor">
+ <NInput v-model:value="model.auditor" placeholder="璇疯緭鍏ュ鏍镐汉" />
+ </NFormItem>
+ <NFormItem label="鍒涘缓浜�" path="creater">
+ <NInput v-model:value="model.creater" placeholder="璇疯緭鍏ュ垱寤轰汉" />
+ </NFormItem>
+ <NFormItem label="鍒惰〃鏃ユ湡" path="tabDate">
+ <NDatePicker
+ v-model:formatted-value="model.tabDate"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鐗堟湰鍚嶇О" path="verName">
+ <NInput v-model:value="model.verName" placeholder="璇疯緭鍏ョ増鏈悕绉�" />
+ </NFormItem>
+ <NFormItem label="鐗堟湰缂栧彿" path="verCode">
+ <NInput v-model:value="model.verCode" placeholder="璇疯緭鍏ョ増鏈紪鍙�" />
+ </NFormItem>
+ <NFormItem label="淇濆瓨鏈�" path="archDate">
+ <NInput v-model:value="model.archDate" placeholder="璇疯緭鍏ヤ繚瀛樻湡" />
+ </NFormItem>
+ <NFormItem label="鍙嶉MES" path="flag">
+ <NSelect v-model:value="model.flag" :options="flagOptions" placeholder="璇烽�夋嫨鍙嶉MES" clearable />
+ </NFormItem>
+ <NFormItem label="涓婁紶MES鏃堕棿" path="toMesDate">
+ <NDatePicker
+ v-model:formatted-value="model.toMesDate"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="浠嶮ES鏃堕棿涓嬭浇" path="fromMesDate">
+ <NDatePicker
+ v-model:formatted-value="model.fromMesDate"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鍒犻櫎鏍囧織" path="deleted">
+ <NInput v-model:value="model.deleted" placeholder="璇疯緭鍏ュ垹闄ゆ爣蹇�" />
+ </NFormItem>
+ <NFormItem label="鎵规鎻忚堪" path="batchDes">
+ <NInput v-model:value="model.batchDes" placeholder="璇疯緭鍏ユ壒娆℃弿杩�" />
+ </NFormItem>
+ <NFormItem label="绫诲埆" path="category">
+ <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="璇烽�夋嫨绫诲埆" clearable />
+ </NFormItem>
+ <NFormItem label="鍗峰埗宸ュ彿" path="makeno">
+ <NInput v-model:value="model.makeno" placeholder="璇疯緭鍏ュ嵎鍒跺伐鍙�" />
+ </NFormItem>
+ <NFormItem label="鐝鏈哄彿" path="shifteqpno">
+ <NInput v-model:value="model.shifteqpno" placeholder="璇疯緭鍏ョ彮娆℃満鍙�" />
+ </NFormItem>
+ <NFormItem label="瑁呯鍙�" path="boxno">
+ <NInput v-model:value="model.boxno" placeholder="璇疯緭鍏ヨ绠卞彿" />
+ </NFormItem>
+ <NFormItem label="鐖舵壒娆″彿" path="pid">
+ <NInput v-model:value="model.pid" placeholder="璇疯緭鍏ョ埗鎵规鍙�" />
+ </NFormItem>
+ <NFormItem label="澶嶆牳浜�" path="reviewer">
+ <NInput v-model:value="model.reviewer" placeholder="璇疯緭鍏ュ鏍镐汉" />
+ </NFormItem>
+ <NFormItem label="澶嶆娆℃暟" path="rvcount">
+ <NInput v-model:value="model.rvcount" placeholder="璇疯緭鍏ュ妫�娆℃暟" />
+ </NFormItem>
+ <NFormItem label="鎵规鐘舵��" path="state">
+ <NInput v-model:value="model.state" placeholder="璇疯緭鍏ユ壒娆$姸鎬�" />
+ </NFormItem>
+ <NFormItem label="澶嶆牳鏃ユ湡" path="reviewTime">
+ <NDatePicker
+ v-model:formatted-value="model.reviewTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="瀹℃牳鏃ユ湡" path="auditTime">
+ <NDatePicker
+ v-model:formatted-value="model.auditTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="瑙勬牸" path="spec">
+ <NInput v-model:value="model.spec" placeholder="璇疯緭鍏ヨ鏍�" />
+ </NFormItem>
+ <NFormItem label="鎵瑰噯鏃堕棿" path="approveTime">
+ <NDatePicker
+ v-model:formatted-value="model.approveTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鍒拌揣鍗曚綅" path="unit">
+ <NInput v-model:value="model.unit" placeholder="璇疯緭鍏ュ埌璐у崟浣�" />
+ </NFormItem>
+ <NFormItem label="鍒拌揣鏃ユ湡" path="arrivalTime">
+ <NDatePicker
+ v-model:formatted-value="model.arrivalTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="瀛樻斁鍦扮偣" path="storagePlace">
+ <NInput v-model:value="model.storagePlace" placeholder="璇疯緭鍏ュ瓨鏀惧湴鐐�" />
+ </NFormItem>
+ <NFormItem label="妫�楠屽憳" path="checker">
+ <NInput v-model:value="model.checker" placeholder="璇疯緭鍏ユ楠屽憳" />
+ </NFormItem>
+ <NFormItem label="鎺ュ崟鏃ユ湡" path="receiveTime">
+ <NDatePicker
+ v-model:formatted-value="model.receiveTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="鎶ユ鏃ユ湡" path="inspTime">
+ <NDatePicker
+ v-model:formatted-value="model.inspTime"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItem>
+ <NFormItem label="浠撳簱淇濈鍛�" path="storer">
+ <NInput v-model:value="model.storer" placeholder="璇疯緭鍏ヤ粨搴撲繚绠″憳" />
+ </NFormItem>
+ <NFormItem label="鏄惁楠岃瘉" path="isverify">
+ <NInput v-model:value="model.isverify" placeholder="璇疯緭鍏ユ槸鍚﹂獙璇�" />
+ </NFormItem>
+ <NFormItem label="鏄惁妫�楠�" path="ischk">
+ <NInput v-model:value="model.ischk" placeholder="璇疯緭鍏ユ槸鍚︽楠�" />
+ </NFormItem>
+ <NFormItem label="澶囩敤1" path="bak1">
+ <NInput v-model:value="model.bak1" placeholder="璇疯緭鍏ュ鐢�1" />
+ </NFormItem>
+ <NFormItem label="澶囩敤2" path="bak2">
+ <NInput v-model:value="model.bak2" placeholder="璇疯緭鍏ュ鐢�2" />
+ </NFormItem>
+ </NForm>
+ <template #footer>
+ <NSpace :size="16">
+ <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
+ <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
+ </NSpace>
+ </template>
+ </NDrawerContent>
+ </NDrawer>
+</template>
+
+<style scoped></style>
diff --git a/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue
new file mode 100644
index 0000000..599f7ec
--- /dev/null
+++ b/ruoyi-plus-soybean/src/views/qm/batch/modules/batch-search.vue
@@ -0,0 +1,150 @@
+<script setup lang="ts">
+import { ref, toRaw } from 'vue';
+import { jsonClone } from '@sa/utils';
+import { useNaiveForm } from '@/hooks/common/form';
+import { $t } from '@/locales';
+
+defineOptions({
+ name: 'BatchSearch'
+});
+
+interface Emits {
+ (e: 'search'): void;
+}
+
+const emit = defineEmits<Emits>();
+
+const { formRef, validate, restoreValidation } = useNaiveForm();
+
+const dateRangeToMesDate = ref<[string, string] | null>(null);
+const dateRangeFromMesDate = ref<[string, string] | null>(null);
+const model = defineModel<Api.Qm.BatchSearchParams>('model', { required: true });
+
+const defaultModel = jsonClone(toRaw(model.value));
+
+// 绫诲瀷閫夐」锛欰-鍒朵笣 B-鎴愬瀷 C-鍗峰寘 D-灏佺 E-绯栭鏂�
+const typOptions = [
+ { label: '鍒朵笣', value: 'A' },
+ { label: '鎴愬瀷', value: 'B' },
+ { label: '鍗峰寘', value: 'C' },
+ { label: '灏佺', value: 'D' },
+ { label: '绯栭鏂�', value: 'E' }
+];
+
+// 鍙嶉MES閫夐」锛�0-鏈笂浼爉es 1-宸蹭笂浼� 3-浠嶮ES涓嬭浇
+const flagOptions = [
+ { label: '鏈笂浼爉es', value: '0' },
+ { label: '宸蹭笂浼�', value: '1' },
+ { label: '浠嶮ES涓嬭浇', value: '3' }
+];
+
+// 绫诲埆閫夐」锛�0-鎴愬搧 1-杈呮潗
+const categoryOptions = [
+ { label: '鎴愬搧', value: '0' },
+ { label: '杈呮潗', value: '1' }
+];
+
+function resetModel() {
+ dateRangeToMesDate.value = null;
+ dateRangeFromMesDate.value = null;
+ Object.assign(model.value, defaultModel);
+}
+
+async function reset() {
+ await restoreValidation();
+ resetModel();
+ emit('search');
+}
+
+async function search() {
+ await validate();
+ if (dateRangeToMesDate.value?.length) {
+ model.value.params!.beginToMesDate = dateRangeToMesDate.value[0];
+ model.value.params!.endToMesDate = dateRangeToMesDate.value[1];
+ }
+ if (dateRangeFromMesDate.value?.length) {
+ model.value.params!.beginFromMesDate = dateRangeFromMesDate.value[0];
+ model.value.params!.endFromMesDate = dateRangeFromMesDate.value[1];
+ }
+ emit('search');
+}
+</script>
+
+<template>
+ <NCard :bordered="false" size="small" class="card-wrapper">
+ <NCollapse>
+ <NCollapseItem :title="$t('common.search')" name="qm-batch-search">
+ <NForm ref="formRef" :model="model" label-placement="left" :label-width="80">
+ <NGrid responsive="screen" item-responsive>
+ <NFormItemGi span="24 s:12 m:8" label="鎵规浠g爜" label-width="auto" path="batchCode" class="pr-24px">
+ <NInput v-model:value="model.batchCode" placeholder="璇疯緭鍏ユ壒娆′唬鐮�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="绫诲瀷" label-width="auto" path="typ" class="pr-24px">
+ <NSelect v-model:value="model.typ" :options="typOptions" placeholder="璇烽�夋嫨绫诲瀷" clearable />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鏈哄彴浠g爜" label-width="auto" path="eqpCode" class="pr-24px">
+ <NInput v-model:value="model.eqpCode" placeholder="璇疯緭鍏ユ満鍙颁唬鐮�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鐗屽彿" label-width="auto" path="matCode" class="pr-24px">
+ <NInput v-model:value="model.matCode" placeholder="璇疯緭鍏ョ墝鍙�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鎵规鐢熸垚鏃ユ湡" label-width="auto" path="batchDate" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="model.batchDate"
+ type="datetime"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鍙嶉MES" label-width="auto" path="flag" class="pr-24px">
+ <NSelect v-model:value="model.flag" :options="flagOptions" placeholder="璇烽�夋嫨鍙嶉MES" clearable />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="涓婁紶MES鏃堕棿" label-width="auto" path="toMesDate" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="dateRangeToMesDate"
+ type="datetimerange"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="浠嶮ES鏃堕棿涓嬭浇" label-width="auto" path="fromMesDate" class="pr-24px">
+ <NDatePicker
+ v-model:formatted-value="dateRangeFromMesDate"
+ type="datetimerange"
+ value-format="yyyy-MM-dd HH:mm:ss"
+ clearable
+ />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鍒犻櫎鏍囧織" label-width="auto" path="deleted" class="pr-24px">
+ <NInput v-model:value="model.deleted" placeholder="璇疯緭鍏ュ垹闄ゆ爣蹇�" />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="绫诲埆" label-width="auto" path="category" class="pr-24px">
+ <NSelect v-model:value="model.category" :options="categoryOptions" placeholder="璇烽�夋嫨绫诲埆" clearable />
+ </NFormItemGi>
+ <NFormItemGi span="24 s:12 m:8" label="鎵规鐘舵��" label-width="auto" path="state" class="pr-24px">
+ <NInput v-model:value="model.state" placeholder="璇疯緭鍏ユ壒娆$姸鎬�" />
+ </NFormItemGi>
+ <NFormItemGi :show-feedback="false" span="24" class="pr-24px">
+ <NSpace class="w-full" justify="end">
+ <NButton @click="reset">
+ <template #icon>
+ <icon-ic-round-refresh class="text-icon" />
+ </template>
+ {{ $t('common.reset') }}
+ </NButton>
+ <NButton type="primary" ghost @click="search">
+ <template #icon>
+ <icon-ic-round-search class="text-icon" />
+ </template>
+ {{ $t('common.search') }}
+ </NButton>
+ </NSpace>
+ </NFormItemGi>
+ </NGrid>
+ </NForm>
+ </NCollapseItem>
+ </NCollapse>
+ </NCard>
+</template>
+
+<style scoped></style>
--
Gitblit v1.9.3