41 Commits

Author SHA1 Message Date
dde35d639b 烘胶房库位新增 2026-07-03 15:21:10 +08:00
99987d9d2e 烘胶房及烘胶分类新增 2026-07-03 09:57:58 +08:00
2240e58355 胶料快检完善 2026-07-02 10:07:31 +08:00
765bc6aaa6 胶料快检曲线图展示优化 2026-06-30 17:56:35 +08:00
geht
e79698c19f 优化用户数据表列配置,移除不必要的可调整属性 2026-06-30 17:52:44 +08:00
geht
ec04a7e1ad 列宽调整 2026-06-30 17:45:15 +08:00
d55223a1c0 胶料快检添加离线模式 2026-06-30 14:43:48 +08:00
672259c94f Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-30 11:28:09 +08:00
840e68a450 胶料快检添加离线模式 2026-06-30 11:28:04 +08:00
51029374fd Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-29 13:33:16 +08:00
15cc5c2879 小料需求计划 2026-06-29 13:33:13 +08:00
efcd73a565 桌面端快检记录新增列表及同步mes 2026-06-22 17:38:49 +08:00
3bce685f3a Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-18 15:18:14 +08:00
c54d54b40f 桌面端密炼计划、胶料快检调整 2026-06-18 15:18:11 +08:00
geht
a9b3720446 Merge branch '20260519-3.9.2版本-葛昊天分支' 2026-06-18 10:56:14 +08:00
geht
73a22b5ed9 中间表采集新增采集配置,实现可视化可控采集 2026-06-18 10:55:11 +08:00
372dc10be2 桌面端新增密炼计划获取 2026-06-17 17:52:31 +08:00
816af5df6e 密炼生产计划维护表更改 2026-06-17 16:39:39 +08:00
2ec2b6a628 Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-17 15:47:59 +08:00
7d7198b802 密炼生产计划优化 2026-06-17 15:47:53 +08:00
1c982052d3 Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-17 15:41:13 +08:00
94b15e5237 桌面端胶料快检实验标准添加 2026-06-17 15:41:06 +08:00
geht
ba77a95554 优化中间库配置加载逻辑,新增启动时加载最近更新的配置功能,提升系统稳定性和灵活性 2026-06-17 10:58:34 +08:00
geht
e28352f8ea 优化生产环境多数据源报错 2026-06-16 18:41:35 +08:00
geht
97a1543e97 frontend build dist update 2026-06-16 18:19:57 +08:00
geht
d40a339aec 优化半自动更新功能,修复已知问题并增强稳定性 2026-06-16 18:12:24 +08:00
geht
54a132de46 优化半自动更新功能,提升用户体验 2026-06-16 17:31:40 +08:00
geht
c96833b339 Merge branch '20260519-3.9.2版本-葛昊天分支' 2026-06-16 16:59:54 +08:00
geht
9147e62977 半自动更新 2026-06-16 16:59:05 +08:00
380de8c54b Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-16 15:35:57 +08:00
7f0f8a3a2f 快检标准新增 2026-06-16 15:35:54 +08:00
geht
44f9a3a197 Merge branch '20260519-3.9.2版本-葛昊天分支' 2026-06-16 14:06:08 +08:00
geht
276c808d7a 上辅机中间库的连接,改成可视化连接方式,可手动配置,放入第三方配置。 2026-06-16 14:05:10 +08:00
be215d604d Merge remote-tracking branch 'origin/生产及设备基础资料' 2026-06-15 16:41:47 +08:00
geht
33b969fc70 优化混炼示方新增时选择机台逻辑 2026-06-15 15:19:47 +08:00
geht
ece8e590e4 混炼示方优化 2026-06-12 19:38:33 +08:00
75bc744fc8 Merge branch 'main' of http://27.223.88.102:33000/chenx/qhmes 2026-06-11 10:06:33 +08:00
3431cc6b17 生产环节优化 2026-06-11 10:06:26 +08:00
geht
5cb24c582d MES审批复用钉钉审批设置 2026-06-10 16:57:07 +08:00
geht
617d47a3db MES本地审批共用钉钉审批等配置 2026-06-10 16:33:44 +08:00
cbbbabe4cf 设备停机记录、设备报警记录新增 2026-06-05 14:17:43 +08:00
2939 changed files with 47311 additions and 538 deletions

View File

@@ -0,0 +1,67 @@
---
name: karpathy-guidelines
description: Behavioral guidelines to reduce common LLM coding mistakes. Use when writing, reviewing, or refactoring code to avoid overcomplication, make surgical changes, surface assumptions, and define verifiable success criteria.
license: MIT
---
# Karpathy Guidelines
Behavioral guidelines to reduce common LLM coding mistakes, derived from [Andrej Karpathy's observations](https://x.com/karpathy/status/2015883857489522876) on LLM coding pitfalls.
**Tradeoff:** These guidelines bias toward caution over speed. For trivial tasks, use judgment.
## 1. Think Before Coding
**Don't assume. Don't hide confusion. Surface tradeoffs.**
Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.
## 2. Simplicity First
**Minimum code that solves the problem. Nothing speculative.**
- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.
Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.
## 3. Surgical Changes
**Touch only what you must. Clean up only your own mess.**
When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.
When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.
The test: Every changed line should trace directly to the user's request.
## 4. Goal-Driven Execution
**Define success criteria. Loop until verified.**
Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"
For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```
Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.

31
build-frontend.bat Normal file
View File

@@ -0,0 +1,31 @@
@echo off
setlocal
set REPO=%~dp0
set WEBDIST=%REPO%web-dist
echo [1/4] build frontend (pnpm install + build) ...
cd /d %REPO%jeecgboot-vue3
call pnpm install
if errorlevel 1 ( echo [ERROR] pnpm install failed & pause & exit /b 1 )
call pnpm run build
if errorlevel 1 ( echo [ERROR] frontend build failed & pause & exit /b 1 )
if not exist "%REPO%jeecgboot-vue3\dist\index.html" ( echo [ERROR] dist/index.html not found & pause & exit /b 1 )
echo [2/4] refresh web-dist folder ...
if exist "%WEBDIST%" rmdir /S /Q "%WEBDIST%"
mkdir "%WEBDIST%"
xcopy "%REPO%jeecgboot-vue3\dist\*" "%WEBDIST%\" /E /Y /I >nul
echo [3/4] git add and commit web-dist ...
cd /d %REPO%
git add web-dist
git commit -m "frontend build dist update"
echo [4/4] git push ...
git push
if errorlevel 1 ( echo [ERROR] git push failed & pause & exit /b 1 )
echo.
echo ===== FRONTEND BUILT AND PUSHED. Now run deploy-frontend.bat on the server. =====
endlocal
pause

26
build.bat Normal file
View File

@@ -0,0 +1,26 @@
@echo off
setlocal
echo ========================================
echo QH-MES Backend Quick Build
echo ========================================
cd /d %~dp0jeecg-boot
echo [1/2] Building start module and its dependencies...
call mvn clean package -pl jeecg-module-system/jeecg-system-start -am -DskipTests -T 1C
if errorlevel 1 (
echo.
echo [FAILED] Build error, please check the log above.
pause
exit /b 1
)
echo.
echo [2/2] Build SUCCESS!
echo Output: %~dp0jeecg-boot\jeecg-module-system\jeecg-system-start\target\jeecg-system-start-3.9.2.jar
echo.
explorer "%~dp0jeecg-boot\jeecg-module-system\jeecg-system-start\target"
endlocal
pause

27
deploy-frontend.bat Normal file
View File

@@ -0,0 +1,27 @@
@echo off
setlocal
set SRC=D:\qhmes-src
set GIT="C:\Program Files\Git\cmd\git.exe"
set WEB=D:\qhmes\nginx-1.30.1\html\jeecg
set NGINX_DIR=D:\qhmes\nginx-1.30.1
echo [1/3] git pull ...
cd /d %SRC%
%GIT% pull
if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 )
if not exist "%SRC%\web-dist\index.html" ( echo [ERROR] web-dist not found in repo, run build-frontend.bat first & pause & exit /b 1 )
echo [2/3] replace nginx frontend files ...
if exist "%WEB%" rmdir /S /Q "%WEB%"
mkdir "%WEB%"
xcopy "%SRC%\web-dist\*" "%WEB%\" /E /Y /I >nul
if errorlevel 1 ( echo [ERROR] copy failed & pause & exit /b 1 )
echo [3/3] reload nginx (ignore error if nginx not running) ...
cd /d %NGINX_DIR%
nginx.exe -s reload
echo.
echo ===== FRONTEND DEPLOY DONE =====
endlocal
pause

36
deploy-server.bat Normal file
View File

@@ -0,0 +1,36 @@
@echo off
setlocal
set SRC=D:\qhmes-src
set GIT="C:\Program Files\Git\cmd\git.exe"
set DEPLOY_DIR=D:\qhmes
set JAR_NAME=jeecg-system-start-3.9.2.jar
set SVC=D:\qhmes\qhmes-service.exe
set BUILT_JAR=%SRC%\jeecg-boot\jeecg-module-system\jeecg-system-start\target\%JAR_NAME%
echo [1/5] git pull ...
cd /d %SRC%
%GIT% pull
if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 )
echo [2/5] maven package with prod profile ...
cd /d %SRC%\jeecg-boot
call mvn clean package -pl jeecg-module-system/jeecg-system-start -am -DskipTests -P prod -T 1C
if errorlevel 1 ( echo [ERROR] build failed & pause & exit /b 1 )
if not exist "%BUILT_JAR%" ( echo [ERROR] built jar not found & pause & exit /b 1 )
echo [3/5] stop service ...
"%SVC%" stop
timeout /t 6 /nobreak >nul
echo [4/5] copy new jar ...
copy /Y "%BUILT_JAR%" "%DEPLOY_DIR%\%JAR_NAME%"
if errorlevel 1 ( echo [ERROR] copy failed, jar locked? & pause & exit /b 1 )
echo [5/5] start service ...
"%SVC%" start
echo.
echo ===== DEPLOY DONE =====
echo Check log: powershell -Command "Get-Content D:\qhmes\logs\qhmes-service.out.log -Wait -Tail 50"
endlocal
pause

View File

@@ -0,0 +1,282 @@
# QH-MES 部署与热部署方案
> 本文档记录 QH-MES(jeecg-boot 3.9.2)在 Windows Server 上的部署方案,包含后端、前端的一键发版流程、关键配置、踩过的坑,以及未来上线客户正式服务器的规划。
> 最后更新:2026-06-17
---
## 一、环境概况
### 测试服务器(当前)
- **系统**:Windows Server 2016 Standard
- **JDK**:17.0.11(`C:\Program Files\Java\jdk-17`,注意 `JAVA_HOME` 要指根目录,**不能带 `\bin`**)
- **Maven**:3.9.8(`D:\apache-maven-3.9.8`,从本地 Win11 拷过去的,因服务器网络受限无法在线下载)
- **Git**:已装在 `C:\Program Files\Git`,但不在 PATH(用完整路径 `"C:\Program Files\Git\cmd\git.exe"` 调用)
- **Gitea**:跑在**同一台机器**,裸仓库在 `D:\gitea\data\gitea-repositories\chenx\qhmes.git`,Web 地址 `http://27.223.88.102:33000/chenx/qhmes`
- **Nginx**:1.30.1,装在 `D:\qhmes\nginx-1.30.1\`,前端文件目录 `D:\qhmes\nginx-1.30.1\html\jeecg\`
- **Node/pnpm/npm**:**服务器上没装**(前端不在服务器构建)
### 关键路径
| 用途 | 路径 |
|------|------|
| 后端运行目录(jar + WinSW 服务) | `D:\qhmes\` |
| 后端运行 jar | `D:\qhmes\jeecg-system-start-3.9.2.jar` |
| 服务器源码工作副本 | `D:\qhmes-src\`(从本地裸仓库 clone,分支 `main`) |
| 前端 nginx 目录 | `D:\qhmes\nginx-1.30.1\html\jeecg\` |
| WinSW 服务程序/配置 | `D:\qhmes\qhmes-service.exe` / `qhmes-service.xml` |
| 后端发版脚本 | `D:\deploy-server.bat`(放源码目录外,避免 git pull 自我覆盖) |
### 本地开发机(Win11)
- 项目路径:`D:\XSL-PROJECT\QH-MES\qhmes`
- 后端模块:`jeecg-boot/`,前端:`jeecgboot-vue3/`(同一个 git 仓库)
- 传文件到服务器的方式:**向日葵远程传输**(只能手动,不能脚本化)
---
## 二、后端部署(已跑通 ✅)
### 2.1 后端做成 Windows 服务(WinSW)
后端不再手动 `java -jar`(关窗口/断 RDP 就掉),改用 **WinSW** 注册成 Windows 服务,开机自启、崩溃自动重启。
- 服务 id:`qhmes`,名称:`QH-MES Backend`
- 配置文件 `D:\qhmes\qhmes-service.xml` 关键内容:
```xml
<executable>java</executable>
<arguments>-Xms1g -Xmx2g -jar "D:\qhmes\jeecg-system-start-3.9.2.jar"</arguments>
<workingdirectory>D:\qhmes</workingdirectory>
<logpath>D:\qhmes\logs</logpath>
<onfailure action="restart" delay="10 sec"/>
```
- **注意**:`<arguments>` 里**不加** `--spring.profiles.active`,因为 profile 已在打包时烤进 jar(见第四节)。
- 常用命令(管理员):
```
D:\qhmes\qhmes-service.exe install # 安装服务(一次性)
D:\qhmes\qhmes-service.exe start # 启动
D:\qhmes\qhmes-service.exe stop # 停止
```
- 查日志:
```powershell
Get-Content D:\qhmes\logs\qhmes-service.out.log -Wait -Tail 60
```
启动成功标志:`Started JeecgSystemApplication in xx seconds`,Tomcat 监听 8888。
### 2.2 一键发版脚本 `D:\deploy-server.bat`
流程:`git pull → mvn 打包(prod) → 停服务 → 换 jar → 启服务`。脚本自带 `git pull`,**双击即自动拉最新代码**。
```bat
@echo off
setlocal
set SRC=D:\qhmes-src
set GIT="C:\Program Files\Git\cmd\git.exe"
set DEPLOY_DIR=D:\qhmes
set JAR_NAME=jeecg-system-start-3.9.2.jar
set SVC=D:\qhmes\qhmes-service.exe
set BUILT_JAR=%SRC%\jeecg-boot\jeecg-module-system\jeecg-system-start\target\%JAR_NAME%
echo [1/5] git pull ...
cd /d %SRC%
%GIT% pull
if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 )
echo [2/5] maven package with prod profile ...
cd /d %SRC%\jeecg-boot
call mvn clean package -pl jeecg-module-system/jeecg-system-start -am -DskipTests -P prod -T 1C
if errorlevel 1 ( echo [ERROR] build failed & pause & exit /b 1 )
if not exist "%BUILT_JAR%" ( echo [ERROR] built jar not found & pause & exit /b 1 )
echo [3/5] stop service ...
"%SVC%" stop
timeout /t 6 /nobreak >nul
echo [4/5] copy new jar ...
copy /Y "%BUILT_JAR%" "%DEPLOY_DIR%\%JAR_NAME%"
if errorlevel 1 ( echo [ERROR] copy failed, jar locked? & pause & exit /b 1 )
echo [5/5] start service ...
"%SVC%" start
echo ===== DEPLOY DONE =====
endlocal
pause
```
### 2.3 后端发版流程
1. 本地改代码 → `git push`(推到 `main`)
2. RDP/向日葵到服务器 → 双击 `D:\deploy-server.bat`
3. 看日志确认 `Started ... in xx seconds`
> 首次构建会下载几百 MB 依赖(约 8 分钟),缓存在 `D:\maven-repo`,之后每次只需 1~3 分钟。
---
## 三、前端部署(脚本已就绪)
前端 `jeecgboot-vue3` 用 **pnpm** 构建,产物 `dist/`,放到 nginx 的 `html\jeecg\`。
因服务器没 Node 且网络受限,**前端不在服务器构建**,而是:**本地构建 → dist 走 git → 服务器拉取替换**。
> `jeecgboot-vue3/dist` 被 `.gitignore` 忽略,所以构建后复制到根目录 **`web-dist`** 文件夹(未被忽略)再提交。
### 3.1 本地构建脚本 `build-frontend.bat`(本地 Win11 双击)
核心构建步骤与官网一致:`pnpm install` + `pnpm run build`,之后自动复制 dist 到 web-dist 并 git push。
```bat
@echo off
setlocal
set REPO=%~dp0
set WEBDIST=%REPO%web-dist
echo [1/4] build frontend (pnpm install + build) ...
cd /d %REPO%jeecgboot-vue3
call pnpm install
if errorlevel 1 ( echo [ERROR] pnpm install failed & pause & exit /b 1 )
call pnpm run build
if errorlevel 1 ( echo [ERROR] frontend build failed & pause & exit /b 1 )
if not exist "%REPO%jeecgboot-vue3\dist\index.html" ( echo [ERROR] dist/index.html not found & pause & exit /b 1 )
echo [2/4] refresh web-dist folder ...
if exist "%WEBDIST%" rmdir /S /Q "%WEBDIST%"
mkdir "%WEBDIST%"
xcopy "%REPO%jeecgboot-vue3\dist\*" "%WEBDIST%\" /E /Y /I >nul
echo [3/4] git add and commit web-dist ...
cd /d %REPO%
git add web-dist
git commit -m "frontend build dist update"
echo [4/4] git push ...
git push
if errorlevel 1 ( echo [ERROR] git push failed & pause & exit /b 1 )
echo ===== FRONTEND BUILT AND PUSHED =====
endlocal
pause
```
### 3.2 服务器部署脚本 `D:\deploy-frontend.bat`(服务器双击)
```bat
@echo off
setlocal
set SRC=D:\qhmes-src
set GIT="C:\Program Files\Git\cmd\git.exe"
set WEB=D:\qhmes\nginx-1.30.1\html\jeecg
set NGINX_DIR=D:\qhmes\nginx-1.30.1
echo [1/3] git pull ...
cd /d %SRC%
%GIT% pull
if errorlevel 1 ( echo [ERROR] git pull failed & pause & exit /b 1 )
if not exist "%SRC%\web-dist\index.html" ( echo [ERROR] web-dist not found, run build-frontend.bat first & pause & exit /b 1 )
echo [2/3] replace nginx frontend files ...
if exist "%WEB%" rmdir /S /Q "%WEB%"
mkdir "%WEB%"
xcopy "%SRC%\web-dist\*" "%WEB%\" /E /Y /I >nul
if errorlevel 1 ( echo [ERROR] copy failed & pause & exit /b 1 )
echo [3/3] reload nginx (ignore error if not running) ...
cd /d %NGINX_DIR%
nginx.exe -s reload
echo ===== FRONTEND DEPLOY DONE =====
endlocal
pause
```
> **nginx 不用重启**:静态文件替换后自动生效。`nginx -s reload` 是平滑重载,**不要直接跑 `nginx.exe`**(会报端口占用)。
### 3.3 前端发版流程(两步双击)
1. 本地双击 `build-frontend.bat`(构建 + 推送 web-dist)
2. 服务器双击 `D:\deploy-frontend.bat`(拉取 + 替换 + reload)
3. 刷新浏览器
---
## 四、配置(profile)说明 —— 重点
### 4.1 哪个配置生效,由打包时的 Maven `-P` 决定
`application.yml``spring.profiles.active: '@profile.name@'` 是 Maven 占位符,打包时填入:
| 打包命令 | 生效配置 |
|---------|---------|
| `mvn package`(不带 -P) | **dev**(默认,`<activeByDefault>` 在 dev 上) |
| `mvn package -P prod` | **prod** |
| `mvn package -P test` | test |
> 发版脚本用的是 **`-P prod`**,所以烤进 jar 的是 prod 配置,运行时无需再加 `--spring.profiles.active`。
### 4.2 判断一个 jar 用的哪个配置
- 看启动日志:`The following 1 profile is active: "prod"`
- 解压 jar 看 `BOOT-INF/classes/application.yml``active` 的实际值
- 运行时 `--spring.profiles.active=xxx` 可强制覆盖
### 4.3 dev vs prod 的区别(本项目)
| 项 | dev | prod(当前测试服务器用) |
|----|-----|------|
| 端口 | 8888 | 8888(已改成与现网一致) |
| MySQL | `xsl.qdxsl.top:50768`(公网绕一圈) | `127.0.0.1:3306`(本机直连) |
| MySQL 密码 | 123456 | 123456(已改,原为 root) |
> **重要事实**:`xsl.qdxsl.top:50768` 与本机 `127.0.0.1:3306` 是**同一个生产库**(公网域名+端口转发到本机)。prod 走本机直连更快更稳。
> prod 配置的修改在 `application-prod.yml`,已带 `update-begin/update-end` 痕迹注释。
---
## 五、踩过的坑(避免重复)
1. **bat 文件乱码/无法执行**:bat 里写中文 + 存成 UTF-8,cmd 按 GBK 读会乱码,连 `@echo off` 都坏。→ **bat 只用英文 ASCII,不带 BOM**
2. **WinSW 报 `Invalid character in encoding`**:xml 里中文存成了 ANSI/GBK。→ 用 UTF-8 保存,或描述改英文。
3. **服务用 prod 启动报 `Access denied for user 'root'`**:prod 密码原写的 `root`,实际应为 `123456`
4. **PowerShell 下载报 `未能创建 SSL/TLS 安全通道`**:Server 2016 默认 TLS 1.0。→ 先 `[Net.ServicePointManager]::SecurityProtocol = ... -bor 3072` 开启 TLS 1.2。
5. **服务器下载被 `127.0.0.1:10080` 的本机 Apache 拦截 404**:服务器网络有本机代理/DNS 劫持,外网下载不通。→ Maven/Node 等**在本地下好,向日葵拷过去**。
6. **`mvn``JAVA_HOME not defined correctly`**:`JAVA_HOME` 误设成了 `...\jdk-17\bin`。→ 应为根目录 `...\jdk-17`
7. **`git clone D:\gitea\...qhmes.git` 拿到的没有源码**:那是 Gitea 裸仓库(只有 git 底层数据)。→ `git clone` 它到 `D:\qhmes-src` 得到工作副本。
8. **cmd 里 `cd D:\xxx` 不切盘**:要用 `cd /d D:\xxx`;`&` 是 PowerShell 语法,cmd 里不能用。
9. **PowerShell 粘贴 here-string 卡在 `>>`**:终止符 `'@` 没识别。→ 大段内容改用**记事本**另存为(All Files + ANSI),或写进 git 拉取。
---
## 六、未来上线客户正式服务器的规划(待落地)
**核心原则:测试服务器可以 git 拉源码+构建;客户正式服务器只部署"已构建的成品",不放源码、不装构建工具、不依赖我方 gitea。**
### 6.1 目标流程
```
我方(测试服务器/开发机):打包出成品(jar + 前端dist)并测好
↓ 向日葵/U盘/网盘 传过去
客户正式服务器:双击 deploy.bat → 停服务 → 换jar → 换前端 → 启服务
```
### 6.2 必做改造:配置外置(同一 jar 走天下)
现在 prod 配置(数据库/IP/密码)烤死在 jar 里,是测试服务器的。客户的库不同,需把配置挪到 jar 外:
```
D:\qhmes\
├── jeecg-system-start-3.9.2.jar ← 所有环境通用,不用为每个客户重打
└── config\
└── application-prod.yml ← 本机专属:客户的数据库/IP/密码
```
Spring Boot 自动优先读 jar 同级 `config\` 目录的配置(外部 > jar 内 classpath)。
### 6.3 待办(上线时找 Claude 做)
1. 把 prod 配置从 jar 内挪到外部 `config\`,jar 变环境无关
2. 写"打 release 包"脚本:一键产出 `jar + 前端dist + deploy.bat` 发布包
3. 写客户服务器 `deploy.bat`:只"换文件+重启",不构建、不拉源码
4. (建议)测试服务器也提前切到外置配置,与客户环境保持一致,上线零改动
---
## 七、快速命令速查
```powershell
# 后端发版
D:\deploy-server.bat # 服务器双击
# 前端发版
build-frontend.bat # 本地 Win11 双击
D:\deploy-frontend.bat # 服务器双击
# 看后端日志
Get-Content D:\qhmes\logs\qhmes-service.out.log -Wait -Tail 60
# 后端服务控制(管理员)
D:\qhmes\qhmes-service.exe stop|start|status
# nginx 平滑重载(在 nginx 目录下)
cd /d D:\qhmes\nginx-1.30.1
nginx.exe -s reload
```

View File

@@ -0,0 +1,60 @@
-- MES 设备报警记录设备停机记录菜单 + 导出按钮 + 租户 admin 授权 MySQL 业务表
-- 权限前缀mes:mes_xsl_equip_alarm_record:* / mes:mes_xsl_equip_downtime_record:*
-- 父菜单设备管理FlywayV3.9.2_124__mes_xsl_equip_mcs_alarm_downtime_menu.sql
SET NAMES utf8mb4;
SET @mes_tenant_id = 1002;
SET @mes_equip_pid = (
SELECT `id` FROM `sys_permission`
WHERE `del_flag` = 0 AND `menu_type` = 0 AND `name` = '设备管理'
LIMIT 1
);
SET @mes_equip_pid = IFNULL(@mes_equip_pid, '1860000000000000133');
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `url`, `component`, `component_name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `keep_alive`, `internal_or_external`, `create_by`, `create_time`)
VALUES ('1860000000000000222', @mes_equip_pid, '设备报警记录', '/xslmes/mesXslEquipAlarmRecord', 'xslmes/mesXslEquipAlarmRecord/MesXslEquipAlarmRecordList', 'MesXslEquipAlarmRecordList', 1, NULL, '1', 13, 1, 0, 0, '1', 0, 1, 0, 'admin', NOW())
ON DUPLICATE KEY UPDATE
`parent_id` = VALUES(`parent_id`), `name` = VALUES(`name`), `url` = VALUES(`url`), `component` = VALUES(`component`), `component_name` = VALUES(`component_name`),
`menu_type` = VALUES(`menu_type`), `perms` = VALUES(`perms`), `perms_type` = VALUES(`perms_type`), `sort_no` = VALUES(`sort_no`),
`is_route` = VALUES(`is_route`), `is_leaf` = VALUES(`is_leaf`), `hidden` = VALUES(`hidden`), `status` = VALUES(`status`), `del_flag` = VALUES(`del_flag`),
`keep_alive` = VALUES(`keep_alive`), `internal_or_external` = VALUES(`internal_or_external`);
UPDATE `sys_permission` SET `icon` = 'ant-design:alert-outlined' WHERE `id` = '1860000000000000222' AND `del_flag` = 0;
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `status`, `del_flag`, `create_by`, `create_time`) VALUES
('1860000000000000223', '1860000000000000222', '导出', 2, 'mes:mes_xsl_equip_alarm_record:exportXls', '1', '1', 0, 'admin', NOW())
ON DUPLICATE KEY UPDATE
`parent_id` = VALUES(`parent_id`), `name` = VALUES(`name`), `menu_type` = VALUES(`menu_type`), `perms` = VALUES(`perms`), `perms_type` = VALUES(`perms_type`),
`status` = VALUES(`status`), `del_flag` = VALUES(`del_flag`);
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `url`, `component`, `component_name`, `menu_type`, `perms`, `perms_type`, `sort_no`, `is_route`, `is_leaf`, `hidden`, `status`, `del_flag`, `keep_alive`, `internal_or_external`, `create_by`, `create_time`)
VALUES ('1860000000000000224', @mes_equip_pid, '设备停机记录', '/xslmes/mesXslEquipDowntimeRecord', 'xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecordList', 'MesXslEquipDowntimeRecordList', 1, NULL, '1', 15, 1, 0, 0, '1', 0, 1, 0, 'admin', NOW())
ON DUPLICATE KEY UPDATE
`parent_id` = VALUES(`parent_id`), `name` = VALUES(`name`), `url` = VALUES(`url`), `component` = VALUES(`component`), `component_name` = VALUES(`component_name`),
`menu_type` = VALUES(`menu_type`), `perms` = VALUES(`perms`), `perms_type` = VALUES(`perms_type`), `sort_no` = VALUES(`sort_no`),
`is_route` = VALUES(`is_route`), `is_leaf` = VALUES(`is_leaf`), `hidden` = VALUES(`hidden`), `status` = VALUES(`status`), `del_flag` = VALUES(`del_flag`),
`keep_alive` = VALUES(`keep_alive`), `internal_or_external` = VALUES(`internal_or_external`);
UPDATE `sys_permission` SET `icon` = 'ant-design:pause-circle-outlined' WHERE `id` = '1860000000000000224' AND `del_flag` = 0;
INSERT INTO `sys_permission`(`id`, `parent_id`, `name`, `menu_type`, `perms`, `perms_type`, `status`, `del_flag`, `create_by`, `create_time`) VALUES
('1860000000000000225', '1860000000000000224', '导出', 2, 'mes:mes_xsl_equip_downtime_record:exportXls', '1', '1', 0, 'admin', NOW())
ON DUPLICATE KEY UPDATE
`parent_id` = VALUES(`parent_id`), `name` = VALUES(`name`), `menu_type` = VALUES(`menu_type`), `perms` = VALUES(`perms`), `perms_type` = VALUES(`perms_type`),
`status` = VALUES(`status`), `del_flag` = VALUES(`del_flag`);
INSERT INTO `sys_role_permission`(`id`, `role_id`, `permission_id`, `operate_date`, `operate_ip`)
SELECT REPLACE(UUID(), '-', ''), r.`id`, p.`id`, NOW(), '127.0.0.1'
FROM `sys_role` r
CROSS JOIN `sys_permission` p
WHERE r.`tenant_id` = @mes_tenant_id
AND r.`role_code` = 'admin'
AND p.`id` IN (
'1860000000000000222', '1860000000000000223',
'1860000000000000224', '1860000000000000225'
)
AND NOT EXISTS (
SELECT 1 FROM `sys_role_permission` rp
WHERE rp.`role_id` = r.`id` AND rp.`permission_id` = p.`id`
);

View File

@@ -0,0 +1,79 @@
-- 密炼生产计划维护 菜单与权限挂载到 MES密炼工程
SET NAMES utf8mb4;
SET @mixer_parent_id = (
SELECT id
FROM sys_permission
WHERE name = 'MES密炼工程' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
);
SET @mixer_parent_id = IFNULL(@mixer_parent_id, (
SELECT id
FROM sys_permission
WHERE url = '/mes' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
));
SET @mixer_parent_id = IFNULL(@mixer_parent_id, '1860000000000000001');
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1860000000000000301',@mixer_parent_id,'密炼生产计划维护','/mes/mixingproductionplaninfo','mes/mixingproductionplaninfo/index','MesXslMixingProductionPlanList',1,NULL,'1',90,0,'ant-design:calendar-outlined',1,1,1,0,0,'密炼生产计划维护',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),
`name`=VALUES(`name`),
`url`=VALUES(`url`),
`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),
`menu_type`=VALUES(`menu_type`),
`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),
`is_leaf`=VALUES(`is_leaf`),
`keep_alive`=VALUES(`keep_alive`),
`icon`=VALUES(`icon`),
`status`=VALUES(`status`),
`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1860000000000000302','1860000000000000301','查询',2,'xslmes:mes_xsl_mixing_production_plan:list','1',1,'1',0,'admin',NOW()),
('1860000000000000303','1860000000000000301','整表保存',2,'xslmes:mes_xsl_mixing_production_plan:saveAll','1',2,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),
`perms`=VALUES(`perms`),
`sort_no`=VALUES(`sort_no`),
`status`=VALUES(`status`),
`del_flag`=VALUES(`del_flag`);
-- admin 角色授权
INSERT INTO sys_role_permission(id, role_id, permission_id, operate_date, operate_ip)
SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', p.id, NOW(), '127.0.0.1'
FROM sys_permission p
WHERE p.id IN (
'1860000000000000301',
'1860000000000000302', '1860000000000000303'
)
AND NOT EXISTS (
SELECT 1
FROM sys_role_permission rp
WHERE rp.role_id = 'f6817f48af4fb3af11b9e8bf182f618b'
AND rp.permission_id = p.id
);
-- 强制修复确保菜单路由与组件路径正确
UPDATE sys_permission
SET
parent_id = @mixer_parent_id,
url = '/mes/mixingproductionplaninfo',
component = 'mes/mixingproductionplaninfo/index',
component_name = 'MesXslMixingProductionPlanList',
menu_type = 1,
is_route = 1,
is_leaf = 1,
hidden = 0,
status = '1',
del_flag = 0
WHERE id = '1860000000000000301';

View File

@@ -0,0 +1,78 @@
-- 原材料需求计划 菜单与权限挂载到 MES密炼工程兼容 MES管理
SET NAMES utf8mb4;
SET @raw_parent_id = (
SELECT id
FROM sys_permission
WHERE name = 'MES密炼工程' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
);
SET @raw_parent_id = IFNULL(@raw_parent_id, (
SELECT id
FROM sys_permission
WHERE url = '/mes' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
));
SET @raw_parent_id = IFNULL(@raw_parent_id, '1860000000000000001');
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1900000000000000710',@raw_parent_id,'原材料需求计划','/mes/rawmaterialdemandplan','mes/rawmaterialdemandplan/index','MesXslRawMaterialDemandPlanList',1,NULL,'1',95,0,'ant-design:ordered-list-outlined',1,1,1,0,0,'原材料需求计划',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),
`name`=VALUES(`name`),
`url`=VALUES(`url`),
`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),
`menu_type`=VALUES(`menu_type`),
`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),
`is_leaf`=VALUES(`is_leaf`),
`keep_alive`=VALUES(`keep_alive`),
`icon`=VALUES(`icon`),
`status`=VALUES(`status`),
`hidden`=VALUES(`hidden`),
`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1900000000000000711','1900000000000000710','导出',2,'xslmes:mes_xsl_raw_material_demand_plan:exportXls','1',1,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),
`perms`=VALUES(`perms`),
`sort_no`=VALUES(`sort_no`),
`status`=VALUES(`status`),
`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_role_permission(id, role_id, permission_id, operate_date, operate_ip)
SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', p.id, NOW(), '127.0.0.1'
FROM sys_permission p
WHERE p.id IN ('1900000000000000710', '1900000000000000711')
AND NOT EXISTS (
SELECT 1
FROM sys_role_permission rp
WHERE rp.role_id = 'f6817f48af4fb3af11b9e8bf182f618b'
AND rp.permission_id = p.id
);
-- 强制修复 ID + 名称 + URL 三重兜底确保能显示
UPDATE sys_permission
SET
parent_id = @raw_parent_id,
url = '/mes/rawmaterialdemandplan',
component = 'mes/rawmaterialdemandplan/index',
component_name = 'MesXslRawMaterialDemandPlanList',
menu_type = 1,
is_route = 1,
is_leaf = 1,
hidden = 0,
status = '1',
del_flag = 0,
redirect = NULL
WHERE id = '1900000000000000710'
OR name = '原材料需求计划'
OR url = '/mes/rawmaterialdemandplan';

View File

@@ -0,0 +1,76 @@
-- 自动/人工小料需求计划 菜单与权限挂载到 MES密炼工程兼容 MES管理
SET NAMES utf8mb4;
SET @small_parent_id = (
SELECT id
FROM sys_permission
WHERE name = 'MES密炼工程' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
);
SET @small_parent_id = IFNULL(@small_parent_id, (
SELECT id
FROM sys_permission
WHERE url = '/mes' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
));
SET @small_parent_id = IFNULL(@small_parent_id, '1860000000000000001');
-- 自动小料需求计划
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1900000000000000720',@small_parent_id,'自动小料需求计划','/mes/autosmallmaterialdemandplan','mes/autosmallmaterialdemandplan/index','MesXslAutoSmallMaterialDemandPlanList',1,NULL,'1',96,0,'ant-design:ordered-list-outlined',1,1,1,0,0,'自动小料需求计划',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),`name`=VALUES(`name`),`url`=VALUES(`url`),`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),`menu_type`=VALUES(`menu_type`),`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),`is_leaf`=VALUES(`is_leaf`),`keep_alive`=VALUES(`keep_alive`),`icon`=VALUES(`icon`),
`status`=VALUES(`status`),`hidden`=VALUES(`hidden`),`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1900000000000000721','1900000000000000720','导出',2,'xslmes:mes_xsl_auto_small_material_demand_plan:exportXls','1',1,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),`perms`=VALUES(`perms`),`sort_no`=VALUES(`sort_no`),`status`=VALUES(`status`),`del_flag`=VALUES(`del_flag`);
-- 人工小料需求计划
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1900000000000000730',@small_parent_id,'人工小料需求计划','/mes/manualsmallmaterialdemandplan','mes/manualsmallmaterialdemandplan/index','MesXslManualSmallMaterialDemandPlanList',1,NULL,'1',97,0,'ant-design:ordered-list-outlined',1,1,1,0,0,'人工小料需求计划',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),`name`=VALUES(`name`),`url`=VALUES(`url`),`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),`menu_type`=VALUES(`menu_type`),`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),`is_leaf`=VALUES(`is_leaf`),`keep_alive`=VALUES(`keep_alive`),`icon`=VALUES(`icon`),
`status`=VALUES(`status`),`hidden`=VALUES(`hidden`),`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1900000000000000731','1900000000000000730','导出',2,'xslmes:mes_xsl_manual_small_material_demand_plan:exportXls','1',1,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),`perms`=VALUES(`perms`),`sort_no`=VALUES(`sort_no`),`status`=VALUES(`status`),`del_flag`=VALUES(`del_flag`);
-- admin 角色授权
INSERT INTO sys_role_permission(id, role_id, permission_id, operate_date, operate_ip)
SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', p.id, NOW(), '127.0.0.1'
FROM sys_permission p
WHERE p.id IN ('1900000000000000720','1900000000000000721','1900000000000000730','1900000000000000731')
AND NOT EXISTS (
SELECT 1 FROM sys_role_permission rp
WHERE rp.role_id = 'f6817f48af4fb3af11b9e8bf182f618b'
AND rp.permission_id = p.id
);
-- 强制修复
UPDATE sys_permission
SET parent_id=@small_parent_id,url='/mes/autosmallmaterialdemandplan',component='mes/autosmallmaterialdemandplan/index',
component_name='MesXslAutoSmallMaterialDemandPlanList',menu_type=1,is_route=1,is_leaf=1,hidden=0,status='1',del_flag=0,redirect=NULL
WHERE id='1900000000000000720' OR name='自动小料需求计划' OR url='/mes/autosmallmaterialdemandplan';
UPDATE sys_permission
SET parent_id=@small_parent_id,url='/mes/manualsmallmaterialdemandplan',component='mes/manualsmallmaterialdemandplan/index',
component_name='MesXslManualSmallMaterialDemandPlanList',menu_type=1,is_route=1,is_leaf=1,hidden=0,status='1',del_flag=0,redirect=NULL
WHERE id='1900000000000000730' OR name='人工小料需求计划' OR url='/mes/manualsmallmaterialdemandplan';

View File

@@ -0,0 +1,75 @@
-- 自动/人工小料计划维护 菜单与权限挂载到 MES密炼工程兼容 MES管理
SET NAMES utf8mb4;
SET @plan_parent_id = (
SELECT id
FROM sys_permission
WHERE name = 'MES密炼工程' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
);
SET @plan_parent_id = IFNULL(@plan_parent_id, (
SELECT id
FROM sys_permission
WHERE url = '/mes' AND menu_type = 0 AND del_flag = 0
ORDER BY create_time ASC
LIMIT 1
));
SET @plan_parent_id = IFNULL(@plan_parent_id, '1860000000000000001');
-- 自动小料计划维护
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1900000000000000740',@plan_parent_id,'自动小料计划维护','/mes/autosmallmaterialplanmaintain','mes/autosmallmaterialplanmaintain/index','MesXslAutoSmallMaterialPlanMaintainList',1,NULL,'1',98,0,'ant-design:table-outlined',1,1,1,0,0,'自动小料计划维护',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),`name`=VALUES(`name`),`url`=VALUES(`url`),`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),`menu_type`=VALUES(`menu_type`),`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),`is_leaf`=VALUES(`is_leaf`),`keep_alive`=VALUES(`keep_alive`),`icon`=VALUES(`icon`),
`status`=VALUES(`status`),`hidden`=VALUES(`hidden`),`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1900000000000000741','1900000000000000740','整表保存',2,'xslmes:mes_xsl_auto_small_material_plan_maintain:saveAll','1',1,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),`perms`=VALUES(`perms`),`sort_no`=VALUES(`sort_no`),`status`=VALUES(`status`),`del_flag`=VALUES(`del_flag`);
-- 人工小料计划维护
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`url`,`component`,`component_name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`always_show`,`icon`,`is_route`,`is_leaf`,`keep_alive`,`hidden`,`hide_tab`,`description`,`status`,`del_flag`,`create_by`,`create_time`,`rule_flag`,`internal_or_external`)
VALUES
('1900000000000000750',@plan_parent_id,'人工小料计划维护','/mes/manualsmallmaterialplanmaintain','mes/manualsmallmaterialplanmaintain/index','MesXslManualSmallMaterialPlanMaintainList',1,NULL,'1',99,0,'ant-design:table-outlined',1,1,1,0,0,'人工小料计划维护',1,0,'admin',NOW(),0,0)
ON DUPLICATE KEY UPDATE
`parent_id`=VALUES(`parent_id`),`name`=VALUES(`name`),`url`=VALUES(`url`),`component`=VALUES(`component`),
`component_name`=VALUES(`component_name`),`menu_type`=VALUES(`menu_type`),`sort_no`=VALUES(`sort_no`),
`is_route`=VALUES(`is_route`),`is_leaf`=VALUES(`is_leaf`),`keep_alive`=VALUES(`keep_alive`),`icon`=VALUES(`icon`),
`status`=VALUES(`status`),`hidden`=VALUES(`hidden`),`del_flag`=VALUES(`del_flag`);
INSERT INTO sys_permission
(`id`,`parent_id`,`name`,`menu_type`,`perms`,`perms_type`,`sort_no`,`status`,`del_flag`,`create_by`,`create_time`)
VALUES
('1900000000000000751','1900000000000000750','整表保存',2,'xslmes:mes_xsl_manual_small_material_plan_maintain:saveAll','1',1,'1',0,'admin',NOW())
ON DUPLICATE KEY UPDATE
`name`=VALUES(`name`),`perms`=VALUES(`perms`),`sort_no`=VALUES(`sort_no`),`status`=VALUES(`status`),`del_flag`=VALUES(`del_flag`);
-- admin授权
INSERT INTO sys_role_permission(id, role_id, permission_id, operate_date, operate_ip)
SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', p.id, NOW(), '127.0.0.1'
FROM sys_permission p
WHERE p.id IN ('1900000000000000740','1900000000000000741','1900000000000000750','1900000000000000751')
AND NOT EXISTS (
SELECT 1 FROM sys_role_permission rp
WHERE rp.role_id = 'f6817f48af4fb3af11b9e8bf182f618b' AND rp.permission_id = p.id
);
-- 强制修正
UPDATE sys_permission
SET parent_id=@plan_parent_id,url='/mes/autosmallmaterialplanmaintain',component='mes/autosmallmaterialplanmaintain/index',
component_name='MesXslAutoSmallMaterialPlanMaintainList',menu_type=1,is_route=1,is_leaf=1,hidden=0,status='1',del_flag=0,redirect=NULL
WHERE id='1900000000000000740' OR name='自动小料计划维护' OR url='/mes/autosmallmaterialplanmaintain';
UPDATE sys_permission
SET parent_id=@plan_parent_id,url='/mes/manualsmallmaterialplanmaintain',component='mes/manualsmallmaterialplanmaintain/index',
component_name='MesXslManualSmallMaterialPlanMaintainList',menu_type=1,is_route=1,is_leaf=1,hidden=0,status='1',del_flag=0,redirect=NULL
WHERE id='1900000000000000750' OR name='人工小料计划维护' OR url='/mes/manualsmallmaterialplanmaintain';

View File

@@ -217,6 +217,12 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon");
// MES密炼物料管理免密接口供桌面端调用
filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon");
// MES密炼生产计划维护免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslMixingProductionPlan/anon/**", "anon");
// MES胶料快检实验标准免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestStd/anon/**", "anon");
// MES胶料快检记录免密接口供桌面端快检记录调用
filterChainDefinitionMap.put("/xslmes/mesXslRubberQuickTestRecord/anon/**", "anon");
// 打印模板免密接口(供桌面端调用)
filterChainDefinitionMap.put("/print/template/anon/**", "anon");
filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon");

View File

@@ -944,6 +944,47 @@ jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixingSpecServiceImpl.java
jeecgboot-vue3/src/views/xslmes/mesXslMixingSpec/components/MesXslMixingSpecModal.vue
-- author:GHT---date:20260610--for: 【IM审批通用化】MES发起审批按钮按ding_tpl_bind路由匹配(与钉钉按钮一致) -----
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/controller/MesXslApprovalLaunchController.java
jeecgboot-vue3/src/components/ApprovalLaunch/index.vue
jeecgboot-vue3/src/views/approval/flow/launch.api.ts
-- author:GHT---date:20260610--for: 【IM审批通用化】IM工作通知公众号(同事列表置顶+审批消息统一推送) -----
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_147__sys_im_work_notify_user.sql
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/impl/SysImChatServiceImpl.java
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/vo/SysImContactVO.java
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/ISysImChatService.java
jeecgboot-vue3/src/views/system/im/ImChat.vue
jeecgboot-vue3/src/views/system/im/imCache.ts
jeecgboot-vue3/src/views/system/im/ImCreateGroupModal.vue
-- author:GHT---date:20260610--for: 【IM审批通用化】审批待办IM发送修复(admin自审重复成员+独立事务防审批回滚) -----
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/impl/SysImChatServiceImpl.java
-- author:GHT---date:20260610--for: 【IM审批通用化】IM卡片字段取值修复(下划线列名+valueMode与钉钉发起对齐) -----
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/service/DingTplImCardBuilder.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/service/DingTplBindFieldValueResolver.java
-- author:GHT---date:20260610--for: 【IM审批通用化】流转中实例支持补发IM审批卡片(审批台账入口) -----
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/service/IMesXslApprovalHandleService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/service/impl/MesXslApprovalHandleServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/controller/MesXslApprovalHandleController.java
jeecgboot-vue3/src/views/approval/flow/approvalHandle.api.ts
jeecgboot-vue3/src/views/xslmes/approval/mesXslApprovalRecord/MesXslApprovalRecordList.vue
-- author:GHT---date:20260610--for: 【IM审批通用化】发起人=处理人时审批待办改由admin代发IM消息 -----
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/ISysImChatService.java
jeecg-boot/jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/im/service/impl/SysImChatServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/service/impl/MesXslApprovalHandleServiceImpl.java
-- author:GHT---date:20260610--for: 【IM审批通用化】IM卡片复用钉钉模板字段+MES回调补齐stageKey走集成方案 -----
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/service/DingTplImCardBuilder.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/service/IMesXslDingTplBindService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/dingtalk/service/impl/MesXslDingTplBindServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/approval/service/impl/MesXslApprovalHandleServiceImpl.java
jeecgboot-vue3/src/views/system/im/imBizRecordMessage.ts
jeecgboot-vue3/src/views/system/im/ImBizRecordMessageContent.vue
-- author:GHT---date:20260610--for: 【混炼示方】TCU温度条件新增是否附加/重量字段 -----
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_146__mes_xsl_mixing_spec_tcu_attach.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java
@@ -993,3 +1034,205 @@ jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMappingList.vue
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMapping.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMapping.api.ts
-- author:GHT---date:20260616--for: 【MES上辅机】SQL Server中间库可视化配置第三方配置页+读写开关+热刷新数据源) ---
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_150__mes_xsl_mcs_db_config.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/entity/MesXslMcsDbConfig.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/mapper/MesXslMcsDbConfigMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsDbConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsDbConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceGuardAspect.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/config/McsDataSourceInitializer.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/controller/MesXslMcsDbConfigController.java
jeecgboot-vue3/src/views/system/appconfig/ThirdAppConfigList.vue
jeecgboot-vue3/src/views/system/appconfig/ThirdAppMcsDbConfigForm.vue
jeecgboot-vue3/src/views/system/appconfig/McsDbConfigModal.vue
jeecgboot-vue3/src/views/system/appconfig/McsDbConfig.data.ts
jeecgboot-vue3/src/views/system/appconfig/McsDbConfig.api.ts
-- author:jiangxh---date:20250603--for: 【MES】设备/质量管理主数据删除前引用校验(统一点检配置等下游阻断) ---
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslDeleteReferenceService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslDeleteReferenceServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslInspectMaintainItemController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipmentCategoryController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipmentTypeController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipmentPartController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipmentSubPartController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipmentLedgerController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslManufacturerController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslSparePartsCategoryController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDowntimeMainTypeController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDowntimeTypeController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipInspectConfigController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestTypeController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestDataPointController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestMethodController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberQuickTestStdController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslRubberSmallLockReasonController.java
-- author:jiangxh---date:20250604--for: 【MES】设备报警记录与设备停机记录SQL Server MCSToMES_MixAlarm 只读、列表回写 ReadTime/MES_Flag ---
jeecg-boot/db/mes-xsl-equip-mcs-alarm-downtime-menu-permission.sql
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_124__mes_xsl_equip_mcs_alarm_downtime_menu.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/vo/MesXslEquipAlarmRecordVO.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/vo/MesXslEquipDowntimeRecordVO.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/util/MesXslMcsMixAlarmConvertUtil.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslEquipAlarmRecordService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslEquipDowntimeRecordService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsMixAlarmReadMarker.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslEquipAlarmRecordServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslEquipDowntimeRecordServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipAlarmRecordController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslEquipDowntimeRecordController.java
jeecgboot-vue3/src/views/xslmes/mesXslEquipAlarmRecord/MesXslEquipAlarmRecord.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslEquipAlarmRecord/MesXslEquipAlarmRecord.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslEquipAlarmRecord/MesXslEquipAlarmRecordList.vue
jeecgboot-vue3/src/views/xslmes/mesXslEquipAlarmRecord/components/MesXslEquipAlarmRecordModal.vue
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecord.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecord.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/MesXslEquipDowntimeRecordList.vue
jeecgboot-vue3/src/views/xslmes/mesXslEquipDowntimeRecord/components/MesXslEquipDowntimeRecordModal.vue
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java
-- author:GHT---date:20260616--for: 【MES上辅机】重启后中间库配置未自动加载租户ID硬编码为0---
原因McsDataSourceInitializer 启动时只查 tenant_id=0页面保存用当前租户如1002重启后查不到配置连接状态回退为 yml。
修改:新增 loadStartupConfig 按最近更新时间加载任意租户配置isDbConfigActive 同时校验数据源是否已注册。
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsDbConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsDbConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/config/McsDataSourceInitializer.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/datasource/McsDataSourceManager.java
-- author:jiangxh---date:20260617--for: 【快检实验标准】补齐 tenant_id 为空的历史数据并恢复租户过滤 ---
原因:一条快检实验标准 tenant_id 为 NULL桌面端按 tenantId=1002 拉取时漏掉该条。
修改Flyway 将 NULL tenant_id 对齐为 1002新增保存时自动写入 tenant_id恢复 anon/list 与桌面端 tenantId 查询参数。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_152__mes_xsl_rubber_quick_test_std_tenant_backfill.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDesktopAnonController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslRubberQuickTestStdServiceImpl.java
yy-admin-master/YY.Admin.Services/Service/RubberQuickTestStd/RubberQuickTestStdService.cs
-- author:GHT---date:20260617--for: 【MES上辅机】密炼动作秒级采集 + 通用中间表采集配置 ---
需求:密炼机动作维护数据从中间表 MCSToMES_MixAct 秒级采集(机台名称→设备名称、动作名称→动作名称、动作地址→动作代号),
在「密炼动作」页支持 启动/停止采集与设置时间间隔默认1秒采集配置落库为通用配置表(mes_xsl_mcs_sync_config)供后续功能复用。
设计:新增通用采集配置表 + McsSyncHandler 扩展点 + McsSyncScheduler(ThreadPoolTaskScheduler 动态重排+启动加载)
MixActSyncHandler 增量 Upsert(按机台编号+动作代号唯一),保留手动维护数据;密炼机动作维护补全 equip_id/equip_type 字段,
唯一性由全局唯一改为(设备+动作代号)同设备内唯一equipment_id 允许为空(采集未匹配台账时)。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_153__mes_xsl_mcs_sync_config.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/entity/MesXslMcsSyncConfig.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/mapper/MesXslMcsSyncConfigMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsSyncConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsSyncConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/controller/MesXslMcsSyncConfigController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/McsSyncHandler.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/McsSyncScheduler.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/handler/MixActSyncHandler.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixerAction.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslMixerActionService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslMixerActionServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslMixerActionController.java
jeecgboot-vue3/src/views/xslmesMcs/mcsToMesMixAct/index.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsToMesMixAct/McsToMesMixAct.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/MesXslMixerAction.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslMixerAction/MesXslMixerAction.api.ts
-- author:GHT---date:20260617--for: 【MES上辅机】密炼动作秒级采集 + 通用中间表采集配置 ---
-- author:GHT---date:20260617--for: 【MES上辅机】采集配置通用表/字段绑定 + 配置驱动采集 ---
需求在「MES上辅机数据」下新增「采集配置」左选中间库表、右选MES表(mes_xsl_前缀)下方左带出中间库字段、右由用户选MES接收字段
采集操作改为弹窗(是否采集+采集间隔),密炼动作页同样改为弹窗。
设计:统一为配置驱动——删除硬编码 MixActSyncHandler/McsSyncHandler新增 GenericMcsSyncEngine(JdbcTemplate跨库读源表→按"匹配键"Upsert写MES表
自动填充 id/时间/租户/del_flag纯字段拷贝)McsSyncScheduler 改为按 configId 调度;新增字段映射表 mes_xsl_mcs_sync_field 与配置头扩展(target_table/config_name等)
密炼动作(MIX_ACT)改造为预置配置+字段映射;新增 McsMetaMapper 查询SQLServer/MySQL表与字段元数据采集配置CRUD/详情/采集操作接口。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_154__mes_xsl_mcs_sync_field.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/entity/MesXslMcsSyncConfig.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/entity/MesXslMcsSyncField.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/mapper/MesXslMcsSyncFieldMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/mapper/McsMetaMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/GenericMcsSyncEngine.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/McsSyncScheduler.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsSyncConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsSyncConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/controller/MesXslMcsSyncConfigController.java
删除jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/McsSyncHandler.java
删除jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/handler/MixActSyncHandler.java
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/index.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/mcsSyncConfig.api.ts
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/mcsSyncConfig.data.ts
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/components/SyncConfigModal.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/components/CollectModal.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsToMesMixAct/index.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsToMesMixAct/McsToMesMixAct.api.ts
-- author:GHT---date:20260617--for: 【MES上辅机】采集配置通用表/字段绑定 + 配置驱动采集 ---
-- author:GHT---date:20260617--for: 【MES上辅机】采集模式全量/时间/增量 + 批量增量写入(应对大表) ---
背景:原通用引擎每周期全表读源+全表读目标逐行Upsertautocommit逐行往返大表(上万~数十万)采集慢。
优化GenericMcsSyncEngine 改为「一次读现有建索引+内存比对+变更检测+batchUpdate分批」并新增三种采集模式(采集操作弹窗可配)
FULL全量匹配(小表全量Upsert)、TIME时间匹配(按时间列取当天/最近七天再Upsert目标侧按窗口匹配键定向IN读取)、
INCR增量匹配(按增量列高水位>last_watermark、ORDER BY ASC取TOP N仅追加并推进水位)。调度器落库 last_watermark。
mes_xsl_mcs_sync_config 增加 sync_mode/incr_column/time_window/batch_limit/last_watermark。
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_155__mes_xsl_mcs_sync_mode.sql
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/entity/MesXslMcsSyncConfig.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/GenericMcsSyncEngine.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/sync/McsSyncScheduler.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/IMesXslMcsSyncConfigService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/service/impl/MesXslMcsSyncConfigServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mcs/controller/MesXslMcsSyncConfigController.java
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/components/CollectModal.vue
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/mcsSyncConfig.api.ts
jeecgboot-vue3/src/views/xslmesMcs/mcsSyncConfig/mcsSyncConfig.data.ts
-- author:GHT---date:20260617--for: 【MES上辅机】采集模式全量/时间/增量 + 批量增量写入(应对大表) ---
-- author:jiangxh---date:20260702--for: 【MES】烘胶房管理MES基础资料无导入导出 ---
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslDryingRoom.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslDryingRoomMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslDryingRoomService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslDryingRoomServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDryingRoomController.java
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_159__mes_xsl_drying_room.sql
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoom/MesXslDryingRoomList.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoom/MesXslDryingRoom.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoom/MesXslDryingRoom.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoom/components/MesXslDryingRoomModal.vue
-- author:jiangxh---date:20260702--for: 【MES】烘胶房管理MES基础资料无导入导出 ---
-- author:jiangxh---date:20260702--for: 【MES】烘胶分类管理主子表+选择物料弹窗,无导入导出) ---
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslDryingCategory.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslDryingCategoryMaterial.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslDryingCategoryMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslDryingCategoryMaterialMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslDryingCategoryService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslDryingCategoryServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDryingCategoryController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/vo/MesXslDryingCategoryPage.java
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_160__mes_xsl_drying_category.sql
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/MesXslDryingCategoryList.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/MesXslDryingCategory.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/MesXslDryingCategory.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/components/MesXslDryingCategoryModal.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/components/MesXslDryingCategoryMixerMaterialSelectModal.vue
-- author:jiangxh---date:20260702--for: 【MES】烘胶分类管理主子表+选择物料弹窗,无导入导出) ---
-- author:jiangxh---date:20260702--for: 【MES】烘胶分类管理补充导出功能 ---
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslDryingCategory.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDryingCategoryController.java
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_160__mes_xsl_drying_category.sql
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_161__mes_xsl_drying_category_export.sql
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/MesXslDryingCategoryList.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingCategory/MesXslDryingCategory.api.ts
-- author:jiangxh---date:20260702--for: 【MES】烘胶分类管理补充导出功能 ---
-- author:jiangxh---date:20260703--for: 【MES】烘胶房库位MES密炼工程含导出引用保护烘胶房/烘胶分类不可删) ---
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslDryingRoomSlot.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslDryingRoomSlotMapper.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslDryingRoomSlotService.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslDryingRoomSlotServiceImpl.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDryingRoomSlotController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslDryingRoomController.java
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslDryingCategoryServiceImpl.java
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_162__mes_xsl_drying_room_slot.sql
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/MesXslDryingRoomSlotList.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/MesXslDryingRoomSlot.data.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/MesXslDryingRoomSlot.api.ts
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/components/MesXslDryingRoomSlotModal.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/components/MesXslDryingRoomSelectModal.vue
jeecgboot-vue3/src/views/xslmes/mesXslDryingRoomSlot/components/MesXslDryingCategorySelectModal.vue
-- author:jiangxh---date:20260703--for: 【MES】烘胶房库位MES密炼工程含导出引用保护烘胶房/烘胶分类不可删) ---

View File

@@ -133,24 +133,18 @@ public class ApprovalCallbackDispatcher {
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());
}
try {
switch (ctx.getAction()) {
case NODE_APPROVED:
cb.onNodeApproved(ctx);
break;
case APPROVED:
cb.onApproved(ctx);
break;
case REJECTED:
cb.onRejected(ctx);
break;
//update-begin---author:GHT ---date:2026-06-08 for【风险修复-R5】分发撤销回调-----------
case CANCELLED:
cb.onCancelled(ctx);
break;
//update-end---author:GHT ---date:2026-06-08 for【风险修复-R5】分发撤销回调-----------
default:
break;
//update-begin---author:cursor ---date:20260615 for【XSLMES-20260615-A05】审批回调分发改用if-else避免调试热更新缺失switch合成类-----------
ApprovalCallbackContext.Action action = ctx.getAction();
if (action == ApprovalCallbackContext.Action.NODE_APPROVED) {
cb.onNodeApproved(ctx);
} else if (action == ApprovalCallbackContext.Action.APPROVED) {
cb.onApproved(ctx);
} else if (action == ApprovalCallbackContext.Action.REJECTED) {
cb.onRejected(ctx);
} else if (action == ApprovalCallbackContext.Action.CANCELLED) {
cb.onCancelled(ctx);
}
//update-end---author:cursor ---date:20260615 for【XSLMES-20260615-A05】审批回调分发改用if-else避免调试热更新缺失switch合成类-----------
if (dingTalk) {
log.info("{} 业务回调完成 {} action={} bizTable={} bizDataId={}",
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());

View File

@@ -7,6 +7,7 @@ import org.jeecg.modules.xslmes.approval.callback.IApprovalBizCallback;
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.springframework.stereotype.Component;
/**
@@ -25,9 +26,13 @@ import org.springframework.stereotype.Component;
public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback {
private final IMesXslRubberQuickTestStdService stdService;
private final MesXslStompNotifyService stompNotify;
public RubberQuickTestStdApprovalCallback(IMesXslRubberQuickTestStdService stdService) {
public RubberQuickTestStdApprovalCallback(
IMesXslRubberQuickTestStdService stdService,
MesXslStompNotifyService stompNotify) {
this.stdService = stdService;
this.stompNotify = stompNotify;
}
@Override
@@ -55,5 +60,8 @@ public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback
.eq(MesXslRubberQuickTestStd::getId, bizDataId)
.set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus)
.update();
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】审批联动 STOMP 同步桌面端-----------
stompNotify.publishRubberQuickTestStdChanged("audit", bizDataId);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】审批联动 STOMP 同步桌面端-----------
}
}

View File

@@ -108,4 +108,20 @@ public class MesXslApprovalHandleController {
return Result.OK(approvalHandleService.pendingList(user));
}
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流完善】待办列表-----
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】补发IM审批卡片(历史流转中实例)-----------
@Operation(summary = "审批办理-补发IM审批卡片(流转中)")
@PostMapping("/resendCard")
public Result<String> resendCard(@RequestBody Map<String, Object> body) {
String instanceId = body.get("instanceId") == null ? null : String.valueOf(body.get("instanceId"));
String bizTable = body.get("bizTable") == null ? null : String.valueOf(body.get("bizTable"));
String bizDataId = body.get("bizDataId") == null ? null : String.valueOf(body.get("bizDataId"));
if (oConvertUtils.isEmpty(instanceId)
&& (oConvertUtils.isEmpty(bizTable) || oConvertUtils.isEmpty(bizDataId))) {
return Result.error("请提供 instanceId 或 bizTable+bizDataId");
}
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
return approvalHandleService.resendCard(instanceId, bizTable, bizDataId, user);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】补发IM审批卡片(历史流转中实例)-----------
}

View File

@@ -16,11 +16,13 @@ import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalHandleService;
import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalInstanceService;
import org.jeecg.modules.xslmes.approval.vo.ApprovalGateVo;
import org.jeecg.modules.xslmes.common.MesXslTenantUtils;
import org.jeecg.modules.xslmes.dingtalk.service.IMesXslDingTplBindService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
@@ -61,19 +63,37 @@ public class MesXslApprovalLaunchController {
@Autowired
private JdbcTemplate jdbcTemplate;
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
@Autowired
private IMesXslDingTplBindService dingTplBindService;
//update-end---author:GHT ---date:20260610 for【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
/**
* 已发布审批流列表(按租户隔离),即"可发起的单据类型"。
* 同时按"功能模块(单据表)"自动反查其菜单路由填入 routePath供前端控制悬浮按钮仅在该功能页显示无需手工配置
* routePath 有值时:与钉钉审批按钮一致,先按 mes_xsl_ding_tpl_bind 解析当前页绑定,再返回该页业务表下已发布审批流
*/
@Operation(summary = "发起审批-已发布审批流列表")
@GetMapping("/publishedList")
public Result<List<MesXslApprovalFlow>> publishedList() {
public Result<List<MesXslApprovalFlow>> publishedList(
@RequestParam(name = "routePath", required = false) String routePath) {
QueryWrapper<MesXslApprovalFlow> qw = new QueryWrapper<>();
qw.eq("status", "1");
Integer tenantId = MesXslTenantUtils.resolveTenantId(null);
if (tenantId != null) {
qw.eq("tenant_id", tenantId);
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
if (oConvertUtils.isNotEmpty(routePath)) {
if (dingTplBindService.resolveActiveByRoutePath(routePath.trim()) == null) {
return Result.OK(Collections.emptyList());
}
String bizTable = resolveTableByRoutePath(routePath);
if (oConvertUtils.isEmpty(bizTable) || !IDENTIFIER.matcher(bizTable).matches()) {
return Result.OK(Collections.emptyList());
}
qw.eq("biz_table", bizTable);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】MES发起按钮与钉钉绑定同路由匹配-----------
qw.orderByDesc("create_time");
List<MesXslApprovalFlow> list = approvalFlowService.list(qw);
// 未手工指定 route_path 时,按单据表名自动反查菜单路由
@@ -90,6 +110,59 @@ public class MesXslApprovalLaunchController {
* 约定jeecg 代码生成的列表组件名为 表名驼峰 + List如 mes_xsl_formula_spec -> MesXslFormulaSpecList
* 对应 sys_permission.component 形如 xslmes/mesXslFormulaSpec/MesXslFormulaSpecList取其 url 即路由。
*/
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】按前端路由反查业务表(与钉钉绑定路由解析一致)-----------
private String resolveTableByRoutePath(String routePath) {
if (oConvertUtils.isEmpty(routePath)) {
return null;
}
String component = resolveComponentByRoutePath(routePath);
if (oConvertUtils.isEmpty(component)) {
return null;
}
String comp = component.contains("/") ? component.substring(component.lastIndexOf('/') + 1) : component;
if (comp.endsWith("List")) {
comp = comp.substring(0, comp.length() - "List".length());
}
return camelToUnderline(comp);
}
private String resolveComponentByRoutePath(String routePath) {
if (oConvertUtils.isEmpty(routePath)) {
return null;
}
String path = routePath.trim().replaceAll("/+$", "");
String sql = "SELECT component FROM sys_permission WHERE menu_type IN (0,1) "
+ "AND (del_flag = 0 OR del_flag IS NULL) AND url = ? "
+ "ORDER BY menu_type DESC LIMIT 1";
try {
List<String> list = jdbcTemplate.queryForList(sql, String.class, path);
return list.isEmpty() ? null : list.get(0);
} catch (Exception e) {
log.warn("反查菜单组件失败 routePath={}", routePath, e);
return null;
}
}
private String camelToUnderline(String camel) {
if (oConvertUtils.isEmpty(camel)) {
return null;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < camel.length(); i++) {
char c = camel.charAt(i);
if (Character.isUpperCase(c)) {
if (i > 0) {
sb.append('_');
}
sb.append(Character.toLowerCase(c));
} else {
sb.append(c);
}
}
return sb.toString();
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】按前端路由反查业务表(与钉钉绑定路由解析一致)-----------
private String resolveRoutePathByTable(String table) {
if (oConvertUtils.isEmpty(table) || !IDENTIFIER.matcher(table).matches()) {
return null;

View File

@@ -57,6 +57,14 @@ public interface IMesXslApprovalHandleService {
Result<String> urge(String instanceId, LoginUser user);
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流完善】催办接口-----
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】流转中实例补发IM审批卡片-----------
/**
* 补发当前节点审批卡片(用于历史数据未收到 IM 消息等场景)。
* instanceId 与 (bizTable+bizDataId) 二选一;仅审批中且 MES 通道实例可补发。
*/
Result<String> resendCard(String instanceId, String bizTable, String bizDataId, LoginUser user);
//update-end---author:GHT ---date:20260610 for【IM审批通用化】流转中实例补发IM审批卡片-----------
//update-begin---author:GHT ---date:2026-05-29 for【QH-MES审批流完善】待办列表查询-----
/**
* 查询当前用户的待办审批列表(状态为审批中且当前处理人包含该用户)。

View File

@@ -23,6 +23,7 @@ import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalHandleService;
import org.jeecg.modules.xslmes.approval.integration.entity.MesXslIntegrationPlan;
import org.jeecg.modules.xslmes.approval.integration.service.IMesXslIntegrationPlanService;
import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalInstanceService;
import org.jeecg.modules.xslmes.dingtalk.service.DingTplImCardBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@@ -100,6 +101,11 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
@Autowired
private IMesXslIntegrationPlanService integrationPlanService;
//update-end---author:GHT ---date:20260605 for【XSLMES-20260605-K8R2】驳回回退改由集成方案 onReject 驱动-----------
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】IM卡片字段与钉钉模板绑定对齐-----------
@Autowired
private DingTplImCardBuilder dingTplImCardBuilder;
//update-end---author:GHT ---date:20260610 for【IM审批通用化】IM卡片字段与钉钉模板绑定对齐-----------
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流设计】审批与业务单据联动回调-----
// ==================== 发起后进入首节点 ====================
@@ -691,11 +697,11 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
oConvertUtils.getString(inst.getApplyUserName(), inst.getApplyUser()), inst.getFlowName(), actionLabel);
msgType = "text";
}
SysUser applicant = getUserSafely(inst.getApplyUser());
String fromId = applicant == null ? null : applicant.getId();
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】待办卡片由系统账号发给处理人,支持发起人=处理人-----------
for (String uname : handlerUsernames) {
sendOne(fromId, uname, inst.getTenantId(), content, msgType);
sendApprovalHandlerNotify(uname, inst.getTenantId(), content, msgType);
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】待办卡片由系统账号发给处理人,支持发起人=处理人-----------
}
/** 抄送通知(无办理按钮) */
@@ -755,6 +761,24 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
}
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】审批待办IM通知-----------
private void sendApprovalHandlerNotify(String toUsername, Integer tenantId, String content, String msgType) {
String uname = toUsername == null ? "" : toUsername.trim();
if (oConvertUtils.isEmpty(uname)) {
return;
}
try {
SysUser to = sysUserService.getUserByName(uname);
if (to == null) {
return;
}
sysImChatService.sendApprovalHandlerMessage(to.getId(), tenantId, content, msgType);
} catch (Exception e) {
log.warn("发送审批待办IM消息失败 to={}", uname, e);
}
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】审批待办IM通知-----------
/** 构建 biz_record 卡片 JSON含 instanceId / actionLabel / canApprove与前端 ImBizRecordPayload 对齐 v=2 */
private String buildCardJson(MesXslApprovalInstance inst, String actionLabel, boolean canApprove, String routePath) {
//update-begin---author:GHT ---date:2026-05-29 for【QH-MES审批流设计】区分审批卡片与抄送通知卡片-----
@@ -766,6 +790,15 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
*/
private String buildCardJson(MesXslApprovalInstance inst, String actionLabel, boolean canApprove, String routePath, boolean approvalCard) {
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流设计】区分审批卡片与抄送通知卡片-----
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】优先按钉钉模板绑定构建卡片字段-----------
MesXslApprovalFlow flow = flowService.getById(inst.getFlowId());
JSONObject dingPayload = dingTplImCardBuilder.buildCardPayload(
inst, flow, actionLabel, canApprove, routePath, approvalCard);
if (dingPayload != null) {
return dingPayload.toJSONString();
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】优先按钉钉模板绑定构建卡片字段-----------
JSONArray fields = new JSONArray();
addField(fields, "审批流", inst.getFlowName());
addField(fields, "单据", safeTitle(inst));
@@ -1353,10 +1386,26 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
if (user != null) {
ctx.setOperatorUsername(user.getUsername());
ctx.setOperatorName(oConvertUtils.getString(user.getRealname(), user.getUsername()));
ctx.setOperatorTime(new Date());
} else {
ctx.setOperatorUsername("system");
ctx.setOperatorName("系统");
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】MES通道补齐stageKey与钉钉回调共用集成方案-----------
if (oConvertUtils.isNotEmpty(nodeId) && oConvertUtils.isNotEmpty(inst.getFlowId())) {
MesXslApprovalFlow flow = flowService.getById(inst.getFlowId());
if (flow != null && oConvertUtils.isNotEmpty(flow.getFlowConfig())) {
JSONObject root = safeParse(flow.getFlowConfig());
JSONObject node = root == null ? null : findNodeById(root, nodeId);
if (node != null) {
JSONObject props = node.getJSONObject("props");
if (props != null && props.containsKey("stageKey")) {
ctx.setStageKey(props.getString("stageKey"));
}
}
}
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】MES通道补齐stageKey与钉钉回调共用集成方案-----------
return ctx;
}
@@ -1455,7 +1504,7 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
if (oConvertUtils.isEmpty(uname)) {
continue;
}
sendOne(user.getId(), uname, inst.getTenantId(),
sendApprovalHandlerNotify(uname, inst.getTenantId(),
"【催办提醒】" + applicantName + " 催促您处理「" + safeTitle(inst) + "」,请尽快审批。", "text");
}
urgeTimeMap.put(instanceId, System.currentTimeMillis());
@@ -1463,6 +1512,77 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
}
//update-end---author:GHT ---date:2026-05-29 for【QH-MES审批流完善】催办发起人向当前处理人发催办提醒-----
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】流转中实例补发IM审批卡片-----------
@Override
public Result<String> resendCard(String instanceId, String bizTable, String bizDataId, LoginUser user) {
if (user == null) {
return Result.error("请先登录");
}
MesXslApprovalInstance inst = resolveRunningInstance(instanceId, bizTable, bizDataId);
if (inst == null) {
return Result.error("未找到审批中的 MES 审批实例");
}
if (!"0".equals(inst.getStatus())) {
return Result.error("该审批已结束,无法补发卡片");
}
if (!canResendCard(user, inst)) {
return Result.error("仅发起人或当前处理人可以补发审批卡片");
}
if (oConvertUtils.isEmpty(inst.getCurrentHandlers())) {
return Result.error("当前无待处理人,无法补发");
}
MesXslApprovalFlow flow = flowService.getById(inst.getFlowId());
if (flow == null) {
return Result.error("审批流不存在");
}
List<String> handlers = new ArrayList<>();
for (String uname : inst.getCurrentHandlers().split(",")) {
if (oConvertUtils.isNotEmpty(uname)) {
handlers.add(uname.trim());
}
}
if (handlers.isEmpty()) {
return Result.error("当前无待处理人,无法补发");
}
String actionLabel = oConvertUtils.getString(inst.getCurrentNodeName(), "审批");
sendApprovalCard(inst, flow, actionLabel, handlers);
return Result.OK("已向 " + handlers.size() + " 位处理人补发审批卡片,请在 IM 中查看与 admin 的会话");
}
private MesXslApprovalInstance resolveRunningInstance(String instanceId, String bizTable, String bizDataId) {
if (oConvertUtils.isNotEmpty(instanceId)) {
MesXslApprovalInstance inst = instanceService.getById(instanceId);
return inst == null || !"0".equals(inst.getStatus()) ? null : inst;
}
if (oConvertUtils.isEmpty(bizTable) || oConvertUtils.isEmpty(bizDataId)
|| !IDENTIFIER.matcher(bizTable).matches()) {
return null;
}
return instanceService.lambdaQuery()
.eq(MesXslApprovalInstance::getBizTable, bizTable)
.eq(MesXslApprovalInstance::getBizDataId, bizDataId)
.eq(MesXslApprovalInstance::getStatus, "0")
.orderByDesc(MesXslApprovalInstance::getCreateTime)
.last("LIMIT 1")
.one();
}
private boolean canResendCard(LoginUser user, MesXslApprovalInstance inst) {
if (user.getUsername().equals(inst.getApplyUser())) {
return true;
}
if (oConvertUtils.isEmpty(inst.getCurrentHandlers())) {
return false;
}
for (String uname : inst.getCurrentHandlers().split(",")) {
if (user.getUsername().equals(uname == null ? "" : uname.trim())) {
return true;
}
}
return false;
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】流转中实例补发IM审批卡片-----------
// ==================== 待办列表 ====================
//update-begin---author:GHT ---date:2026-05-29 for【QH-MES审批流完善】待办列表查询当前用户的待处理审批实例-----

View File

@@ -16,6 +16,10 @@ import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecDownStep;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecMaterial;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecStep;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecTcu;
import org.jeecg.modules.xslmes.vo.MesXslFormulaSpecEditChangeItemVO;
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
@@ -82,6 +86,35 @@ public final class MesXslFormulaSpecEditLogDiffUtil {
return toJson(snapshot);
}
//update-begin---author:cursor ---date:20260612 for【XSLMES-20260612-A03】混炼示方历史快照反序列化-----------
public static MesXslMixingSpecPage parseMixingSnapshotJson(String snapshotJson) {
if (StringUtils.isBlank(snapshotJson)) {
return null;
}
JSONObject root = parseObject(snapshotJson);
if (root == null) {
return null;
}
JSONObject mainObj = root.getJSONObject(SECTION_MAIN);
if (mainObj == null) {
return null;
}
MesXslMixingSpecPage page = mainObj.toJavaObject(MesXslMixingSpecPage.class);
page.setMaterialList(parseSnapshotList(root.getJSONArray(SECTION_MATERIAL), MesXslMixingSpecMaterial.class));
page.setStepList(parseSnapshotList(root.getJSONArray(SECTION_STEP), MesXslMixingSpecStep.class));
page.setDownStepList(parseSnapshotList(root.getJSONArray(SECTION_DOWN_STEP), MesXslMixingSpecDownStep.class));
page.setTcuList(parseSnapshotList(root.getJSONArray(SECTION_TCU), MesXslMixingSpecTcu.class));
return page;
}
private static <T> List<T> parseSnapshotList(JSONArray array, Class<T> clazz) {
if (array == null || array.isEmpty()) {
return new ArrayList<>();
}
return array.toJavaList(clazz);
}
//update-end---author:cursor ---date:20260612 for【XSLMES-20260612-A03】混炼示方历史快照反序列化-----------
public static List<MesXslFormulaSpecEditChangeItemVO> compare(
String specType, String beforeSnapshot, String afterSnapshot) {
List<MesXslFormulaSpecEditChangeItemVO> items = new ArrayList<>();

View File

@@ -0,0 +1,176 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslSmallMaterialDemandPlanSummary;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@Tag(name = "自动小料需求计划")
@RestController
@RequestMapping("/xslmes/mesXslAutoSmallMaterialDemandPlan")
public class MesXslAutoSmallMaterialDemandPlanController {
private static final String TABLE_NAME = "mes_xsl_auto_small_material_demand_plan";
@Autowired private JdbcTemplate jdbcTemplate;
@Operation(summary = "自动小料需求计划-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslSmallMaterialDemandPlanSummary>> queryPageList(
MesXslSmallMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params);
String countSql = "SELECT COUNT(1) FROM (" + groupedSql + ") t";
Long total = jdbcTemplate.queryForObject(countSql, Long.class, params.toArray());
long totalCount = total == null ? 0L : total;
int offset = Math.max((pageNo - 1) * pageSize, 0);
String pageSql = groupedSql + buildOrderBy(groupedByMachine) + " LIMIT ? OFFSET ?";
List<Object> pageParams = new ArrayList<>(params);
pageParams.add(pageSize);
pageParams.add(offset);
List<MesXslSmallMaterialDemandPlanSummary> rows = queryRows(pageSql, pageParams, groupedByMachine);
Page<MesXslSmallMaterialDemandPlanSummary> page = new Page<>(pageNo, pageSize, totalCount);
page.setRecords(rows);
return Result.OK(page);
}
@RequiresPermissions("xslmes:mes_xsl_auto_small_material_demand_plan:exportXls")
@RequestMapping("/exportXls")
public ModelAndView exportXls(
HttpServletRequest request,
MesXslSmallMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params) + buildOrderBy(groupedByMachine);
List<MesXslSmallMaterialDemandPlanSummary> exportList = queryRows(groupedSql, params, groupedByMachine);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "自动小料需求计划");
mv.addObject(NormalExcelConstants.CLASS, MesXslSmallMaterialDemandPlanSummary.class);
mv.addObject(
NormalExcelConstants.PARAMS,
new ExportParams(
"自动小料需求计划",
"导出人:" + (sysUser == null ? "admin" : sysUser.getRealname()),
"自动小料需求计划",
ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if (oConvertUtils.isNotEmpty(exportFields)) {
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
private String buildGroupedSql(
MesXslSmallMaterialDemandPlanSummary query, boolean groupedByMachine, List<Object> params) {
String machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
String statDateExpr = "DATE_FORMAT(t.stat_date, '%Y-%m-%d')";
StringBuilder sql = new StringBuilder();
sql.append("SELECT ");
if (groupedByMachine) {
sql.append(machineExpr).append(" AS machineName, ");
} else {
sql.append("'' AS machineName, ");
}
sql.append(rawMaterialExpr)
.append(" AS rawMaterialName, ")
.append("SUM(COALESCE(t.demand_weight,0)) AS demandWeight, ")
.append("MAX(")
.append(statDateExpr)
.append(") AS statDate ")
.append("FROM ")
.append(TABLE_NAME)
.append(" t ")
.append("WHERE (t.del_flag = 0 OR t.del_flag IS NULL) ");
if (query != null && StringUtils.isNotBlank(query.getStatDate())) {
sql.append("AND ").append(statDateExpr).append(" = ? ");
params.add(query.getStatDate().trim());
}
if (query != null && StringUtils.isNotBlank(query.getRawMaterialName())) {
sql.append("AND ").append(rawMaterialExpr).append(" LIKE ? ");
params.add("%" + query.getRawMaterialName().trim() + "%");
}
if (groupedByMachine && query != null && StringUtils.isNotBlank(query.getMachineName())) {
sql.append("AND ").append(machineExpr).append(" LIKE ? ");
params.add("%" + query.getMachineName().trim() + "%");
}
sql.append("GROUP BY ");
if (groupedByMachine) {
sql.append(machineExpr).append(", ");
}
sql.append(rawMaterialExpr);
return sql.toString();
}
private List<MesXslSmallMaterialDemandPlanSummary> queryRows(
String sql, List<Object> params, boolean groupedByMachine) {
return jdbcTemplate.query(
sql,
rs -> {
List<MesXslSmallMaterialDemandPlanSummary> list = new ArrayList<>();
int seq = 1;
while (rs.next()) {
MesXslSmallMaterialDemandPlanSummary row = new MesXslSmallMaterialDemandPlanSummary();
row.setMachineName(groupedByMachine ? trim(rs.getString("machineName")) : "");
row.setRawMaterialName(trim(rs.getString("rawMaterialName")));
row.setDemandWeight(rs.getBigDecimal("demandWeight"));
row.setStatDate(trim(rs.getString("statDate")));
row.setId(buildRowId(row, groupedByMachine, seq++));
list.add(row);
}
return list;
},
params.toArray());
}
private String buildOrderBy(boolean groupedByMachine) {
if (groupedByMachine) {
return " ORDER BY machineName, rawMaterialName";
}
return " ORDER BY rawMaterialName";
}
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
}
private String trim(String value) {
return value == null ? "" : value.trim();
}
}

View File

@@ -0,0 +1,61 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.xslmes.entity.MesXslAutoSmallMaterialPlanMaintain;
import org.jeecg.modules.xslmes.service.IMesXslAutoSmallMaterialPlanMaintainService;
import org.jeecg.modules.xslmes.vo.MesXslAutoSmallMaterialPlanMaintainSaveAllVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "自动小料计划维护")
@RestController
@RequestMapping("/xslmes/mesXslAutoSmallMaterialPlanMaintain")
public class MesXslAutoSmallMaterialPlanMaintainController
extends JeecgController<
MesXslAutoSmallMaterialPlanMaintain, IMesXslAutoSmallMaterialPlanMaintainService> {
private final IMesXslAutoSmallMaterialPlanMaintainService service;
public MesXslAutoSmallMaterialPlanMaintainController(
IMesXslAutoSmallMaterialPlanMaintainService service) {
this.service = service;
}
@Operation(summary = "自动小料计划维护-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslAutoSmallMaterialPlanMaintain>> queryPageList(
MesXslAutoSmallMaterialPlanMaintain model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "50") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslAutoSmallMaterialPlanMaintain> queryWrapper =
QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.orderByAsc("sort_no").orderByAsc("create_time");
IPage<MesXslAutoSmallMaterialPlanMaintain> pageList =
service.page(new Page<>(pageNo, pageSize), queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "自动小料计划维护-整表保存")
@Operation(summary = "自动小料计划维护-整表保存")
@RequiresPermissions("xslmes:mes_xsl_auto_small_material_plan_maintain:saveAll")
@PostMapping("/saveAll")
public Result<String> saveAll(@RequestBody MesXslAutoSmallMaterialPlanMaintainSaveAllVO req) {
service.saveAllRows(req == null ? null : req.getRows());
return Result.OK("保存成功");
}
}

View File

@@ -1,5 +1,6 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -21,6 +22,7 @@ import org.jeecg.modules.print.entity.PrintTemplate;
import org.jeecg.modules.print.service.IPrintBizTemplateBindService;
import org.jeecg.modules.print.service.IPrintTemplateService;
import org.jeecg.modules.print.util.PrintBizDataMappingUtil;
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus;
import org.jeecg.modules.xslmes.constant.MesXslPrintConstants;
import org.jeecg.modules.xslmes.entity.MesXslCustomer;
@@ -32,6 +34,12 @@ import org.jeecg.modules.xslmes.entity.MesXslUnit;
import org.jeecg.modules.xslmes.entity.MesXslVehicle;
import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
import org.jeecg.modules.xslmes.entity.MesXslWarehouseArea;
import org.jeecg.modules.xslmes.entity.MesXslMixingProductionPlan;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestMethod;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
import org.jeecg.modules.xslmes.entity.MesXslWeightRecord;
import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService;
@@ -42,9 +50,14 @@ import org.jeecg.modules.xslmes.service.IMesXslUnitService;
import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService;
import org.jeecg.modules.xslmes.service.IMesXslWarehouseService;
import org.jeecg.modules.xslmes.service.IMesXslMixingProductionPlanService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
@@ -87,6 +100,10 @@ public class MesXslDesktopAnonController {
private final IPrintBizTemplateBindService printBizTemplateBindService;
private final IPrintTemplateService printTemplateService;
private final ObjectMapper objectMapper;
private final IMesXslMixingProductionPlanService mixingProductionPlanService;
private final IMesXslRubberQuickTestStdService rubberQuickTestStdService;
private final IMesXslRubberQuickTestRecordService rubberQuickTestRecordService;
private final IMesXslRubberQuickTestMethodService rubberQuickTestMethodService;
// ═══════════════════════════ 车辆管理 ═══════════════════════════
@@ -925,6 +942,170 @@ public class MesXslDesktopAnonController {
}
//update-end---author:cursor ---date:20250602 for【密炼物料皮重策略】桌面端单位下拉只读-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端密炼生产计划只读-----------
@Operation(summary = "密炼生产计划维护-免密分页列表查询(供桌面端快检记录筛选)")
@GetMapping("/xslmes/mesXslMixingProductionPlan/anon/list")
public Result<IPage<MesXslMixingProductionPlan>> mixingProductionPlanAnonList(
MesXslMixingProductionPlan model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "500") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslMixingProductionPlan> qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
qw.orderByAsc("sort_no").orderByAsc("create_time");
IPage<MesXslMixingProductionPlan> page =
mixingProductionPlanService.page(new Page<>(pageNo, pageSize), qw);
return Result.OK(page);
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端密炼生产计划只读-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检实验标准】桌面端只读列表与详情-----------
@Operation(summary = "胶料快检实验标准-免密分页列表")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/list")
public Result<IPage<MesXslRubberQuickTestStd>> rubberQuickTestStdAnonList(
MesXslRubberQuickTestStd model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslRubberQuickTestStd> qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
qw.orderByDesc("create_time");
IPage<MesXslRubberQuickTestStd> page = rubberQuickTestStdService.page(new Page<>(pageNo, pageSize), qw);
if (page.getRecords() != null) {
page.getRecords().forEach(this::fillStdQuickTestTypeFromMethod);
}
return Result.OK(page);
}
@Operation(summary = "胶料快检实验标准-免密通过id查询含明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryById")
public Result<MesXslRubberQuickTestStd> rubberQuickTestStdAnonQueryById(@RequestParam(name = "id") String id) {
MesXslRubberQuickTestStd entity = rubberQuickTestStdService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
entity.setLineList(rubberQuickTestStdService.selectLinesByStdId(id));
fillStdQuickTestTypeFromMethod(entity);
return Result.OK(entity);
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检实验标准】桌面端只读列表与详情-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检实验标准查询-----------
private static final String RUBBER_QUICK_TEST_STD_ENABLE_IN_USE = "1";
@Operation(summary = "胶料快检实验标准-免密按胶料名称查询使用中标准及明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryByRubberMaterialName")
public Result<MesXslRubberQuickTestStd> rubberQuickTestStdAnonQueryByRubberMaterialName(
@RequestParam(name = "rubberMaterialName") String rubberMaterialName) {
if (oConvertUtils.isEmpty(rubberMaterialName)) {
return Result.error("胶料名称不能为空");
}
String name = rubberMaterialName.trim();
LambdaQueryWrapper<MesXslRubberQuickTestStd> qw = new LambdaQueryWrapper<>();
qw.eq(MesXslRubberQuickTestStd::getRubberMaterialName, name);
qw.eq(MesXslRubberQuickTestStd::getEnableStatus, RUBBER_QUICK_TEST_STD_ENABLE_IN_USE);
qw.eq(MesXslRubberQuickTestStd::getAuditStatus, XslMesBizConstants.RUBBER_QUICK_TEST_STD_AUDIT_APPROVED);
qw.orderByDesc(MesXslRubberQuickTestStd::getCreateTime);
MesXslRubberQuickTestStd std = rubberQuickTestStdService.getOne(qw, false);
if (std == null) {
return Result.error("未找到胶料「" + name + "」对应的使用中且已批准的快检实验标准");
}
std.setLineList(rubberQuickTestStdService.selectLinesByStdId(std.getId()));
fillStdQuickTestTypeFromMethod(std);
return Result.OK(std);
}
@Operation(summary = "胶料快检实验标准-免密查询明细")
@GetMapping("/xslmes/mesXslRubberQuickTestStd/anon/queryLineListByStdId")
public Result<List<MesXslRubberQuickTestStdLine>> rubberQuickTestStdAnonQueryLineListByStdId(
@RequestParam(name = "id") String id) {
return Result.OK(rubberQuickTestStdService.selectLinesByStdId(id));
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检实验标准查询-----------
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检记录保存-----------
@Operation(summary = "胶料快检记录-免密分页列表")
@GetMapping("/xslmes/mesXslRubberQuickTestRecord/anon/list")
public Result<IPage<MesXslRubberQuickTestRecord>> rubberQuickTestRecordAnonList(
MesXslRubberQuickTestRecord model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslRubberQuickTestRecord> qw = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
qw.orderByDesc("create_time");
IPage<MesXslRubberQuickTestRecord> page = rubberQuickTestRecordService.page(new Page<>(pageNo, pageSize), qw);
return Result.OK(page);
}
@Operation(summary = "胶料快检记录-免密通过id查询含明细")
@GetMapping("/xslmes/mesXslRubberQuickTestRecord/anon/queryById")
public Result<MesXslRubberQuickTestRecord> rubberQuickTestRecordAnonQueryById(@RequestParam(name = "id") String id) {
MesXslRubberQuickTestRecord entity = rubberQuickTestRecordService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
fillRubberQuickTestRecordDetails(entity);
return Result.OK(entity);
}
@Operation(summary = "胶料快检记录-免密添加")
@PostMapping("/xslmes/mesXslRubberQuickTestRecord/anon/add")
public Result<String> rubberQuickTestRecordAnonAdd(@RequestBody MesXslRubberQuickTestRecord record) {
if (record == null) {
return Result.error("参数不能为空");
}
if (oConvertUtils.isEmpty(record.getRubberMaterialName())) {
return Result.error("胶料名称不能为空");
}
if (CollectionUtils.isEmpty(record.getStdLineList())) {
return Result.error("请维护数据标准明细");
}
if (CollectionUtils.isEmpty(record.getRawLineList())) {
return Result.error("请维护试验结果明细");
}
//update-begin---author:jiangxh ---date:20260617 for【快检记录】桌面端同步须含曲线图数据-----------
if (CollectionUtils.isEmpty(record.getChartPointList())) {
return Result.error("请维护曲线图数据");
}
//update-end---author:jiangxh ---date:20260617 for【快检记录】桌面端同步须含曲线图数据-----------
try {
if (oConvertUtils.isEmpty(record.getRecordNo())) {
record.setRecordNo(rubberQuickTestRecordService.generateDesktopRecordNo(record));
}
rubberQuickTestRecordService.fillStdAndTypeForRecord(record);
rubberQuickTestRecordService.saveMain(record, record.getLineList());
stompNotify.publishRubberQuickTestRecordChanged("add", record.getId());
return Result.OK(record.getRecordNo());
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
}
private void fillRubberQuickTestRecordDetails(MesXslRubberQuickTestRecord entity) {
if (entity == null || oConvertUtils.isEmpty(entity.getId())) {
return;
}
String id = entity.getId();
entity.setStdLineList(rubberQuickTestRecordService.selectStdLinesByRecordId(id));
entity.setRawLineList(rubberQuickTestRecordService.selectRawLinesByRecordId(id));
entity.setChartPointList(rubberQuickTestRecordService.selectChartPointsByRecordId(id));
entity.setLineList(rubberQuickTestRecordService.selectLinesByRecordId(id));
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】桌面端胶料快检记录保存-----------
//update-begin---author:jiangxh ---date:20260618 for【快检实验标准】桌面端回填实验方法关联实验类型-----------
private void fillStdQuickTestTypeFromMethod(MesXslRubberQuickTestStd std) {
if (std == null || oConvertUtils.isEmpty(std.getTestMethodId())) {
return;
}
MesXslRubberQuickTestMethod method = rubberQuickTestMethodService.getById(std.getTestMethodId());
if (method == null) {
return;
}
std.setQuickTestTypeId(method.getQuickTestTypeId());
std.setQuickTestTypeName(method.getQuickTestTypeName());
}
//update-end---author:jiangxh ---date:20260618 for【快检实验标准】桌面端回填实验方法关联实验类型-----------
// ─────────────────────────── 车辆私有辅助 ────────────────────────────
private void applyWeightNetAndBillType(MesXslWeightRecord record) {

View File

@@ -25,6 +25,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslDowntimeMainTypeService;
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@@ -53,6 +54,9 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
@Autowired
private IMesXslProcessOperationService mesXslProcessOperationService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES停机主类型-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslDowntimeMainType>> queryPageList(
@@ -104,6 +108,10 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
@RequiresPermissions("mes:mes_xsl_downtime_main_type:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateDowntimeMainTypeDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslDowntimeMainTypeService.removeById(id);
return Result.OK("删除成功!");
}
@@ -113,6 +121,10 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
@RequiresPermissions("mes:mes_xsl_downtime_main_type:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateDowntimeMainTypeDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslDowntimeMainTypeService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -26,6 +26,7 @@ import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
import org.jeecg.modules.xslmes.entity.MesXslDowntimeType;
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslDowntimeMainTypeService;
import org.jeecg.modules.xslmes.service.IMesXslDowntimeTypeService;
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
@@ -59,6 +60,9 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
@Autowired
private IMesXslDowntimeMainTypeService mesXslDowntimeMainTypeService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES停机类型-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslDowntimeType>> queryPageList(
@@ -110,6 +114,10 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
@RequiresPermissions("mes:mes_xsl_downtime_type:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateDowntimeTypeDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslDowntimeTypeService.removeById(id);
return Result.OK("删除成功!");
}
@@ -119,6 +127,10 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
@RequiresPermissions("mes:mes_xsl_downtime_type:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateDowntimeTypeDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslDowntimeTypeService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -0,0 +1,229 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
import org.jeecg.modules.xslmes.entity.MesXslDryingCategory;
import org.jeecg.modules.xslmes.entity.MesXslDryingCategoryMaterial;
import org.jeecg.modules.xslmes.service.IMesXslDryingCategoryService;
import org.jeecg.modules.xslmes.vo.MesXslDryingCategoryPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
/**
* MES 烘胶分类管理(主子表)
*/
@Tag(name = "MES烘胶分类管理")
@RestController
@RequestMapping("/xslmes/mesXslDryingCategory")
@Slf4j
public class MesXslDryingCategoryController
extends JeecgController<MesXslDryingCategory, IMesXslDryingCategoryService> {
/** 母炼胶、终炼胶、塑炼胶(塑料胶)大类 id见 V3.9.2_35__mes_xsl_material_category_tree.sql */
private static final Set<String> ALLOWED_MAJOR_CATEGORY_IDS =
Set.of("1993000000000000104", "1993000000000000105", "1993000000000000103");
@Autowired
private IMesXslDryingCategoryService mesXslDryingCategoryService;
@Autowired
private IMesMixerMaterialService mesMixerMaterialService;
@Operation(summary = "MES烘胶分类管理-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslDryingCategory>> queryPageList(
MesXslDryingCategory model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslDryingCategory> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.orderByDesc("create_time");
Page<MesXslDryingCategory> page = new Page<>(pageNo, pageSize);
IPage<MesXslDryingCategory> pageList = mesXslDryingCategoryService.page(page, queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "MES烘胶分类管理-添加")
@Operation(summary = "MES烘胶分类管理-添加")
@RequiresPermissions("mes:mes_xsl_drying_category:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody MesXslDryingCategoryPage page) {
MesXslDryingCategory main = new MesXslDryingCategory();
BeanUtils.copyProperties(page, main);
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶分类保存校验名称唯一、明细物料大类限制-----------
String err = validateForSave(main, page.getMaterialList(), null);
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶分类保存校验名称唯一、明细物料大类限制-----------
mesXslDryingCategoryService.saveMain(main, page.getMaterialList());
return Result.OK("添加成功!");
}
@AutoLog(value = "MES烘胶分类管理-编辑")
@Operation(summary = "MES烘胶分类管理-编辑")
@RequiresPermissions("mes:mes_xsl_drying_category:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> edit(@RequestBody MesXslDryingCategoryPage page) {
MesXslDryingCategory main = new MesXslDryingCategory();
BeanUtils.copyProperties(page, main);
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶分类保存校验名称唯一、明细物料大类限制-----------
String err = validateForSave(main, page.getMaterialList(), main.getId());
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶分类保存校验名称唯一、明细物料大类限制-----------
mesXslDryingCategoryService.updateMain(main, page.getMaterialList());
return Result.OK("编辑成功!");
}
@AutoLog(value = "MES烘胶分类管理-删除")
@Operation(summary = "MES烘胶分类管理-通过id删除")
@RequiresPermissions("mes:mes_xsl_drying_category:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
mesXslDryingCategoryService.delMain(id);
return Result.OK("删除成功!");
}
@AutoLog(value = "MES烘胶分类管理-批量删除")
@Operation(summary = "MES烘胶分类管理-批量删除")
@RequiresPermissions("mes:mes_xsl_drying_category:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
mesXslDryingCategoryService.delBatchMain(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
@Operation(summary = "MES烘胶分类管理-通过id查询")
@GetMapping(value = "/queryById")
public Result<MesXslDryingCategory> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslDryingCategory entity = mesXslDryingCategoryService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
return Result.OK(entity);
}
@Operation(summary = "MES烘胶分类管理-查询物料明细")
@GetMapping(value = "/queryMaterialListByCategoryId")
public Result<List<MesXslDryingCategoryMaterial>> queryMaterialListByCategoryId(
@RequestParam(name = "id", required = true) String id) {
return Result.OK(mesXslDryingCategoryService.selectMaterialsByCategoryId(id));
}
@Operation(summary = "校验分类名称是否重复同租户未删除数据dataId 为编辑时当前主键)")
@GetMapping(value = "/checkCategoryName")
public Result<String> checkCategoryName(
@RequestParam(name = "categoryName", required = true) String categoryName,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(categoryName) || categoryName.trim().isEmpty()) {
return Result.OK("该值可用!");
}
MesXslDryingCategory ctx = new MesXslDryingCategory();
if (mesXslDryingCategoryService.isCategoryNameDuplicated(categoryName.trim(), dataId, ctx)) {
return Result.error("分类名称不能重复");
}
return Result.OK("该值可用!");
}
@RequiresPermissions("mes:mes_xsl_drying_category:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, MesXslDryingCategory model) {
return super.exportXls(request, model, MesXslDryingCategory.class, "烘胶分类管理");
}
@Operation(summary = "MES烘胶分类-可选密炼物料分页(大类:母炼胶/终炼胶/塑炼胶)")
@GetMapping(value = "/listSelectableMixerMaterials")
public Result<IPage<MesMixerMaterial>> listSelectableMixerMaterials(
MesMixerMaterial model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesMixerMaterial> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.in("major_category_id", ALLOWED_MAJOR_CATEGORY_IDS);
queryWrapper.and(
q -> q.eq("del_flag", CommonConstant.DEL_FLAG_0).or().isNull("del_flag"));
queryWrapper.orderByAsc("material_code");
Page<MesMixerMaterial> page = new Page<>(pageNo, pageSize);
IPage<MesMixerMaterial> pageList = mesMixerMaterialService.page(page, queryWrapper);
return Result.OK(pageList);
}
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶分类保存前校验名称唯一、明细物料不重复且大类受限-----------
private String validateForSave(
MesXslDryingCategory main, List<MesXslDryingCategoryMaterial> materialList, String excludeId) {
if (main == null) {
return "参数不能为空";
}
if (oConvertUtils.isEmpty(main.getCategoryName()) || main.getCategoryName().trim().isEmpty()) {
return "分类名称不能为空";
}
String categoryName = main.getCategoryName().trim();
main.setCategoryName(categoryName);
if (mesXslDryingCategoryService.isCategoryNameDuplicated(categoryName, excludeId, main)) {
return "分类名称不能重复";
}
if (materialList == null || materialList.isEmpty()) {
return "请通过「选择物料」至少添加一条明细";
}
Set<String> materialIds = new HashSet<>();
int sort = 0;
for (int i = 0; i < materialList.size(); i++) {
MesXslDryingCategoryMaterial line = materialList.get(i);
if (line == null) {
continue;
}
int rowNo = i + 1;
if (oConvertUtils.isEmpty(line.getMixerMaterialId())) {
return "" + rowNo + " 行未选择物料";
}
String materialId = line.getMixerMaterialId().trim();
if (!materialIds.add(materialId)) {
return "" + rowNo + " 行物料与前面行重复,同一分类中物料不能重复";
}
MesMixerMaterial material = mesMixerMaterialService.getById(materialId);
if (material == null || isDeleted(material.getDelFlag())) {
return "" + rowNo + " 行物料不存在或已删除";
}
String majorId = material.getMajorCategoryId();
if (oConvertUtils.isEmpty(majorId) || !ALLOWED_MAJOR_CATEGORY_IDS.contains(majorId.trim())) {
return "" + rowNo + " 行物料大类不在允许范围(母炼胶/终炼胶/塑炼胶)";
}
line.setMixerMaterialId(materialId);
line.setMaterialCode(material.getMaterialCode());
line.setMaterialName(material.getMaterialName());
line.setMaterialDesc(material.getMaterialDesc());
line.setSortNo(sort++);
}
if (materialIds.isEmpty()) {
return "请通过「选择物料」至少添加一条明细";
}
return null;
}
private static boolean isDeleted(Integer delFlag) {
return delFlag != null && delFlag.equals(CommonConstant.DEL_FLAG_1);
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶分类保存前校验名称唯一、明细物料不重复且大类受限-----------
}

View File

@@ -0,0 +1,200 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslDryingRoom;
import org.jeecg.modules.xslmes.service.IMesXslDryingRoomService;
import org.jeecg.modules.xslmes.service.IMesXslDryingRoomSlotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* MES 烘胶房管理
*/
@Tag(name = "MES烘胶房管理")
@RestController
@RequestMapping("/xslmes/mesXslDryingRoom")
@Slf4j
public class MesXslDryingRoomController extends JeecgController<MesXslDryingRoom, IMesXslDryingRoomService> {
private static final Pattern MONTH_DAY_PATTERN = Pattern.compile("^(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$");
@Autowired
private IMesXslDryingRoomService mesXslDryingRoomService;
@Autowired
private IMesXslDryingRoomSlotService mesXslDryingRoomSlotService;
@Operation(summary = "MES烘胶房管理-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslDryingRoom>> queryPageList(
MesXslDryingRoom model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslDryingRoom> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
Page<MesXslDryingRoom> page = new Page<>(pageNo, pageSize);
IPage<MesXslDryingRoom> pageList = mesXslDryingRoomService.page(page, queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "MES烘胶房管理-添加")
@Operation(summary = "MES烘胶房管理-添加")
@RequiresPermissions("mes:mes_xsl_drying_room:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody MesXslDryingRoom model) {
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验编码/名称唯一、月日格式-----------
String err = validateForSave(model, null);
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验编码/名称唯一、月日格式-----------
mesXslDryingRoomService.save(model);
return Result.OK("添加成功!");
}
@AutoLog(value = "MES烘胶房管理-编辑")
@Operation(summary = "MES烘胶房管理-编辑")
@RequiresPermissions("mes:mes_xsl_drying_room:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> edit(@RequestBody MesXslDryingRoom model) {
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验编码/名称唯一、月日格式-----------
String err = validateForSave(model, model.getId());
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验编码/名称唯一、月日格式-----------
mesXslDryingRoomService.updateById(model);
return Result.OK("编辑成功!");
}
@AutoLog(value = "MES烘胶房管理-删除")
@Operation(summary = "MES烘胶房管理-通过id删除")
@RequiresPermissions("mes:mes_xsl_drying_room:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
//update-begin---author:jiangxh ---date:20260703 for【MES】被烘胶房库位引用的烘胶房不允许删除-----------
if (mesXslDryingRoomSlotService.countByDryingRoomId(id) > 0) {
return Result.error("该烘胶房已被烘胶房库位引用,不允许删除");
}
//update-end---author:jiangxh ---date:20260703 for【MES】被烘胶房库位引用的烘胶房不允许删除-----------
mesXslDryingRoomService.removeById(id);
return Result.OK("删除成功!");
}
@AutoLog(value = "MES烘胶房管理-批量删除")
@Operation(summary = "MES烘胶房管理-批量删除")
@RequiresPermissions("mes:mes_xsl_drying_room:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
//update-begin---author:jiangxh ---date:20260703 for【MES】被烘胶房库位引用的烘胶房不允许删除-----------
for (String id : ids.split(",")) {
if (oConvertUtils.isNotEmpty(id) && mesXslDryingRoomSlotService.countByDryingRoomId(id.trim()) > 0) {
return Result.error("存在已被烘胶房库位引用的烘胶房,不允许删除");
}
}
//update-end---author:jiangxh ---date:20260703 for【MES】被烘胶房库位引用的烘胶房不允许删除-----------
mesXslDryingRoomService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
@Operation(summary = "MES烘胶房管理-通过id查询")
@GetMapping(value = "/queryById")
public Result<MesXslDryingRoom> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslDryingRoom entity = mesXslDryingRoomService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
return Result.OK(entity);
}
@Operation(summary = "校验烘胶房编码是否重复同租户未删除数据dataId 为编辑时当前主键)")
@GetMapping(value = "/checkRoomCode")
public Result<String> checkRoomCode(
@RequestParam(name = "roomCode", required = true) String roomCode,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(roomCode) || roomCode.trim().isEmpty()) {
return Result.OK("该值可用!");
}
MesXslDryingRoom ctx = new MesXslDryingRoom();
if (mesXslDryingRoomService.isRoomCodeDuplicated(roomCode.trim(), dataId, ctx)) {
return Result.error("烘胶房编码不能重复");
}
return Result.OK("该值可用!");
}
@Operation(summary = "校验烘胶房名称是否重复同租户未删除数据dataId 为编辑时当前主键)")
@GetMapping(value = "/checkRoomName")
public Result<String> checkRoomName(
@RequestParam(name = "roomName", required = true) String roomName,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(roomName) || roomName.trim().isEmpty()) {
return Result.OK("该值可用!");
}
MesXslDryingRoom ctx = new MesXslDryingRoom();
if (mesXslDryingRoomService.isRoomNameDuplicated(roomName.trim(), dataId, ctx)) {
return Result.error("烘胶房名称不能重复");
}
return Result.OK("该值可用!");
}
//update-begin---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验-----------
private String validateForSave(MesXslDryingRoom model, String excludeId) {
if (oConvertUtils.isEmpty(model.getRoomCode()) || model.getRoomCode().trim().isEmpty()) {
return "烘胶房编码不能为空";
}
String roomCode = model.getRoomCode().trim();
model.setRoomCode(roomCode);
if (mesXslDryingRoomService.isRoomCodeDuplicated(roomCode, excludeId, model)) {
return "烘胶房编码不能重复";
}
if (oConvertUtils.isEmpty(model.getRoomName()) || model.getRoomName().trim().isEmpty()) {
return "烘胶房名称不能为空";
}
String roomName = model.getRoomName().trim();
model.setRoomName(roomName);
if (mesXslDryingRoomService.isRoomNameDuplicated(roomName, excludeId, model)) {
return "烘胶房名称不能重复";
}
String startMd = normalizeMonthDay(model.getDryingStartMd(), "烘胶开始日期");
if (startMd == null) {
return "烘胶开始日期格式无效,须为 MM-DD";
}
model.setDryingStartMd(startMd);
String endMd = normalizeMonthDay(model.getDryingEndMd(), "烘胶结束日期");
if (endMd == null) {
return "烘胶结束日期格式无效,须为 MM-DD";
}
model.setDryingEndMd(endMd);
return null;
}
private String normalizeMonthDay(String value, String fieldLabel) {
if (oConvertUtils.isEmpty(value) || value.trim().isEmpty()) {
return null;
}
String md = value.trim();
if (md.length() >= 10 && md.charAt(4) == '-') {
md = md.substring(5, 10);
}
if (!MONTH_DAY_PATTERN.matcher(md).matches()) {
log.warn("{}格式无效: {}", fieldLabel, value);
return null;
}
return md;
}
//update-end---author:jiangxh ---date:20260702 for【MES】烘胶房保存前校验-----------
}

View File

@@ -0,0 +1,193 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslDryingCategory;
import org.jeecg.modules.xslmes.entity.MesXslDryingRoom;
import org.jeecg.modules.xslmes.entity.MesXslDryingRoomSlot;
import org.jeecg.modules.xslmes.service.IMesXslDryingCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslDryingRoomService;
import org.jeecg.modules.xslmes.service.IMesXslDryingRoomSlotService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
/**
* MES 烘胶房库位
*/
@Tag(name = "MES烘胶房库位")
@RestController
@RequestMapping("/xslmes/mesXslDryingRoomSlot")
@Slf4j
public class MesXslDryingRoomSlotController extends JeecgController<MesXslDryingRoomSlot, IMesXslDryingRoomSlotService> {
@Autowired
private IMesXslDryingRoomSlotService mesXslDryingRoomSlotService;
@Autowired
private IMesXslDryingRoomService mesXslDryingRoomService;
@Autowired
private IMesXslDryingCategoryService mesXslDryingCategoryService;
@Operation(summary = "MES烘胶房库位-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslDryingRoomSlot>> queryPageList(
MesXslDryingRoomSlot model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslDryingRoomSlot> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.orderByDesc("create_time");
Page<MesXslDryingRoomSlot> page = new Page<>(pageNo, pageSize);
IPage<MesXslDryingRoomSlot> pageList = mesXslDryingRoomSlotService.page(page, queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "MES烘胶房库位-添加")
@Operation(summary = "MES烘胶房库位-添加")
@RequiresPermissions("mes:mes_xsl_drying_room_slot:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody MesXslDryingRoomSlot model) {
//update-begin---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
String err = validateForSave(model, null);
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
mesXslDryingRoomSlotService.save(model);
return Result.OK("添加成功!");
}
@AutoLog(value = "MES烘胶房库位-编辑")
@Operation(summary = "MES烘胶房库位-编辑")
@RequiresPermissions("mes:mes_xsl_drying_room_slot:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> edit(@RequestBody MesXslDryingRoomSlot model) {
//update-begin---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
String err = validateForSave(model, model.getId());
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
mesXslDryingRoomSlotService.updateById(model);
return Result.OK("编辑成功!");
}
@AutoLog(value = "MES烘胶房库位-删除")
@Operation(summary = "MES烘胶房库位-通过id删除")
@RequiresPermissions("mes:mes_xsl_drying_room_slot:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
mesXslDryingRoomSlotService.removeById(id);
return Result.OK("删除成功!");
}
@AutoLog(value = "MES烘胶房库位-批量删除")
@Operation(summary = "MES烘胶房库位-批量删除")
@RequiresPermissions("mes:mes_xsl_drying_room_slot:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
mesXslDryingRoomSlotService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}
@Operation(summary = "MES烘胶房库位-通过id查询")
@GetMapping(value = "/queryById")
public Result<MesXslDryingRoomSlot> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslDryingRoomSlot entity = mesXslDryingRoomSlotService.getById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
return Result.OK(entity);
}
@Operation(summary = "校验烘胶房库位名称是否重复同烘胶房内未删除数据dataId 为编辑时当前主键)")
@GetMapping(value = "/checkSlotName")
public Result<String> checkSlotName(
@RequestParam(name = "slotName", required = true) String slotName,
@RequestParam(name = "dryingRoomId", required = true) String dryingRoomId,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(slotName) || slotName.trim().isEmpty()) {
return Result.OK("该值可用!");
}
if (oConvertUtils.isEmpty(dryingRoomId)) {
return Result.error("请先选择所属烘胶房");
}
MesXslDryingRoomSlot ctx = new MesXslDryingRoomSlot();
if (mesXslDryingRoomSlotService.isSlotNameDuplicated(slotName.trim(), dryingRoomId, dataId, ctx)) {
return Result.error("该烘胶房内库位名称不能重复");
}
return Result.OK("该值可用!");
}
@RequiresPermissions("mes:mes_xsl_drying_room_slot:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, MesXslDryingRoomSlot model) {
return super.exportXls(request, model, MesXslDryingRoomSlot.class, "烘胶房库位");
}
//update-begin---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
private String validateForSave(MesXslDryingRoomSlot model, String excludeId) {
if (model == null) {
return "参数不能为空";
}
if (oConvertUtils.isEmpty(model.getSlotName()) || model.getSlotName().trim().isEmpty()) {
return "烘胶房库位不能为空";
}
String slotName = model.getSlotName().trim();
model.setSlotName(slotName);
if (oConvertUtils.isEmpty(model.getDryingRoomId())) {
return "请选择所属烘胶房";
}
MesXslDryingRoom room = mesXslDryingRoomService.getById(model.getDryingRoomId().trim());
if (room == null || isDeleted(room.getDelFlag())) {
return "所属烘胶房不存在或已删除";
}
model.setDryingRoomId(room.getId());
model.setDryingRoomName(room.getRoomName());
if (mesXslDryingRoomSlotService.isSlotNameDuplicated(slotName, room.getId(), excludeId, model)) {
return "该烘胶房内库位名称不能重复";
}
if (oConvertUtils.isEmpty(model.getDryingCategoryId())) {
return "请选择存放物料(烘胶分类)";
}
MesXslDryingCategory category = mesXslDryingCategoryService.getById(model.getDryingCategoryId().trim());
if (category == null || isDeleted(category.getDelFlag())) {
return "存放物料分类不存在或已删除";
}
model.setDryingCategoryId(category.getId());
model.setCategoryName(category.getCategoryName());
if (model.getSlotCapacity() == null) {
return "库位容量不能为空";
}
if (model.getSlotCapacity().compareTo(BigDecimal.ZERO) <= 0) {
return "库位容量必须大于0";
}
return null;
}
private static boolean isDeleted(Integer delFlag) {
return delFlag != null && delFlag.equals(CommonConstant.DEL_FLAG_1);
}
//update-end---author:jiangxh ---date:20260703 for【MES】烘胶房库位保存前校验-----------
}

View File

@@ -0,0 +1,86 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
import org.jeecg.modules.xslmes.mcs.service.IMesXslEquipAlarmRecordService;
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipAlarmRecordVO;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
/**
* 设备报警记录(只读,数据来自 SQL Server MCSToMES_MixAlarm
*/
@Tag(name = "MES设备报警记录")
@RestController
@RequestMapping("/xslmes/mesXslEquipAlarmRecord")
@Slf4j
public class MesXslEquipAlarmRecordController {
@Autowired
private IMesXslEquipAlarmRecordService mesXslEquipAlarmRecordService;
@Operation(summary = "MES设备报警记录-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipAlarmRecordVO>> queryPageList(
McsToMesMixAlarm query,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
IPage<MesXslEquipAlarmRecordVO> pageList =
mesXslEquipAlarmRecordService.queryPage(query, req.getParameterMap(), pageNo, pageSize);
return Result.OK(pageList);
}
@Operation(summary = "MES设备报警记录-通过id查询")
@GetMapping(value = "/queryById")
public Result<MesXslEquipAlarmRecordVO> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslEquipAlarmRecordVO entity = mesXslEquipAlarmRecordService.queryById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
return Result.OK(entity);
}
@RequiresPermissions("mes:mes_xsl_equip_alarm_record:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, McsToMesMixAlarm query) {
List<MesXslEquipAlarmRecordVO> exportList =
mesXslEquipAlarmRecordService.listForExport(query, request.getParameterMap());
Subject subject = SecurityUtils.getSubject();
LoginUser sysUser = subject != null && subject.getPrincipal() instanceof LoginUser
? (LoginUser) subject.getPrincipal()
: null;
String exporter = sysUser == null || oConvertUtils.isEmpty(sysUser.getRealname()) ? "admin" : sysUser.getRealname();
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "设备报警记录");
mv.addObject(NormalExcelConstants.CLASS, MesXslEquipAlarmRecordVO.class);
mv.addObject(
NormalExcelConstants.PARAMS,
new ExportParams("设备报警记录", "导出人:" + exporter, "设备报警记录", ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if (oConvertUtils.isNotEmpty(exportFields)) {
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
}

View File

@@ -0,0 +1,86 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
import org.jeecg.modules.xslmes.mcs.service.IMesXslEquipDowntimeRecordService;
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipDowntimeRecordVO;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
/**
* 设备停机记录(只读,数据来自 SQL Server MCSToMES_MixAlarm
*/
@Tag(name = "MES设备停机记录")
@RestController
@RequestMapping("/xslmes/mesXslEquipDowntimeRecord")
@Slf4j
public class MesXslEquipDowntimeRecordController {
@Autowired
private IMesXslEquipDowntimeRecordService mesXslEquipDowntimeRecordService;
@Operation(summary = "MES设备停机记录-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipDowntimeRecordVO>> queryPageList(
McsToMesMixAlarm query,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
IPage<MesXslEquipDowntimeRecordVO> pageList =
mesXslEquipDowntimeRecordService.queryPage(query, req.getParameterMap(), pageNo, pageSize);
return Result.OK(pageList);
}
@Operation(summary = "MES设备停机记录-通过id查询")
@GetMapping(value = "/queryById")
public Result<MesXslEquipDowntimeRecordVO> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslEquipDowntimeRecordVO entity = mesXslEquipDowntimeRecordService.queryById(id);
if (entity == null) {
return Result.error("未找到对应数据");
}
return Result.OK(entity);
}
@RequiresPermissions("mes:mes_xsl_equip_downtime_record:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, McsToMesMixAlarm query) {
List<MesXslEquipDowntimeRecordVO> exportList =
mesXslEquipDowntimeRecordService.listForExport(query, request.getParameterMap());
Subject subject = SecurityUtils.getSubject();
LoginUser sysUser = subject != null && subject.getPrincipal() instanceof LoginUser
? (LoginUser) subject.getPrincipal()
: null;
String exporter = sysUser == null || oConvertUtils.isEmpty(sysUser.getRealname()) ? "admin" : sysUser.getRealname();
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "设备停机记录");
mv.addObject(NormalExcelConstants.CLASS, MesXslEquipDowntimeRecordVO.class);
mv.addObject(
NormalExcelConstants.PARAMS,
new ExportParams("设备停机记录", "导出人:" + exporter, "设备停机记录", ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if (oConvertUtils.isNotEmpty(exportFields)) {
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
}

View File

@@ -23,6 +23,7 @@ import org.jeecg.modules.xslmes.entity.MesXslEquipInspectConfig;
import org.jeecg.modules.xslmes.entity.MesXslEquipInspectConfigLine;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
import org.jeecg.modules.xslmes.entity.MesXslInspectMaintainItem;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipInspectConfigService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
@@ -53,6 +54,9 @@ public class MesXslEquipInspectConfigController
@Autowired
private IMesXslInspectMaintainItemService mesXslInspectMaintainItemService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备点检配置-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipInspectConfig>> queryPageList(
@@ -106,6 +110,10 @@ public class MesXslEquipInspectConfigController
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipInspectConfigDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipInspectConfigService.delMain(id);
return Result.OK("删除成功!");
}
@@ -115,6 +123,10 @@ public class MesXslEquipInspectConfigController
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipInspectConfigDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipInspectConfigService.delBatchMain(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -24,6 +24,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@@ -52,6 +53,9 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
@Autowired
private IMesXslProcessOperationService mesXslProcessOperationService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备类别-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipmentCategory>> queryPageList(
@@ -100,6 +104,10 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
@RequiresPermissions("mes:mes_xsl_equipment_category:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipmentCategoryDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentCategoryService.removeById(id);
return Result.OK("删除成功!");
}
@@ -109,6 +117,10 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
@RequiresPermissions("mes:mes_xsl_equipment_category:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipmentCategoryDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentCategoryService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
@@ -45,6 +46,9 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
@Autowired
private IMesXslEquipmentLedgerService mesXslEquipmentLedgerService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备台账-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipmentLedger>> queryPageList(
@@ -96,6 +100,10 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
@RequiresPermissions("mes:mes_xsl_equipment_ledger:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipmentLedgerDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentLedgerService.removeById(id);
return Result.OK("删除成功!");
}
@@ -105,6 +113,10 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
@RequiresPermissions("mes:mes_xsl_equipment_ledger:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipmentLedgerDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentLedgerService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentPart;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@@ -49,6 +50,9 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
@Autowired
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备部位-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipmentPart>> queryPageList(
@@ -97,6 +101,10 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
@RequiresPermissions("mes:mes_xsl_equipment_part:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipmentPartDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentPartService.removeById(id);
return Result.OK("删除成功!");
}
@@ -106,6 +114,10 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
@RequiresPermissions("mes:mes_xsl_equipment_part:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipmentPartDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentPartService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -23,6 +23,7 @@ import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentPart;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentSubPart;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
@@ -54,6 +55,9 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
@Autowired
private IMesXslEquipmentPartService mesXslEquipmentPartService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备小部位-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipmentSubPart>> queryPageList(
@@ -102,6 +106,10 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipmentSubPartDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentSubPartService.removeById(id);
return Result.OK("删除成功!");
}
@@ -111,6 +119,10 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipmentSubPartDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentSubPartService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -25,6 +25,7 @@ import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
import org.jeecg.modules.xslmes.entity.MesXslEquipmentType;
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
@@ -54,6 +55,9 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
@Autowired
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES设备类型-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslEquipmentType>> queryPageList(
@@ -102,6 +106,10 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
@RequiresPermissions("mes:mes_xsl_equipment_type:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateEquipmentTypeDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentTypeService.removeById(id);
return Result.OK("删除成功!");
}
@@ -111,6 +119,10 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
@RequiresPermissions("mes:mes_xsl_equipment_type:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateEquipmentTypeDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslEquipmentTypeService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresPermissions;
@@ -26,6 +27,7 @@ import org.jeecg.modules.xslmes.service.IMesXslEquipmentCategoryService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -60,6 +62,9 @@ public class MesXslInspectMaintainItemController
@Autowired
private IMesXslEquipmentSubPartService mesXslEquipmentSubPartService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES点检及保养项目-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslInspectMaintainItem>> queryPageList(
@@ -109,6 +114,12 @@ public class MesXslInspectMaintainItemController
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
//update-begin---author:jiangxh ---date:20250603 for【MES】点检及保养项目删除前校验设备点检配置等引用-----------
String err = mesXslDeleteReferenceService.validateInspectMaintainItemDelete(List.of(id));
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20250603 for【MES】点检及保养项目删除前校验设备点检配置等引用-----------
mesXslInspectMaintainItemService.removeById(id);
return Result.OK("删除成功!");
}
@@ -118,6 +129,12 @@ public class MesXslInspectMaintainItemController
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
//update-begin---author:jiangxh ---date:20250603 for【MES】点检及保养项目删除前校验设备点检配置等引用-----------
String err = mesXslDeleteReferenceService.validateInspectMaintainItemDelete(Arrays.asList(ids.split(",")));
if (err != null) {
return Result.error(err);
}
//update-end---author:jiangxh ---date:20250603 for【MES】点检及保养项目删除前校验设备点检配置等引用-----------
mesXslInspectMaintainItemService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -0,0 +1,176 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslSmallMaterialDemandPlanSummary;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@Tag(name = "人工小料需求计划")
@RestController
@RequestMapping("/xslmes/mesXslManualSmallMaterialDemandPlan")
public class MesXslManualSmallMaterialDemandPlanController {
private static final String TABLE_NAME = "mes_xsl_manual_small_material_demand_plan";
@Autowired private JdbcTemplate jdbcTemplate;
@Operation(summary = "人工小料需求计划-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslSmallMaterialDemandPlanSummary>> queryPageList(
MesXslSmallMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params);
String countSql = "SELECT COUNT(1) FROM (" + groupedSql + ") t";
Long total = jdbcTemplate.queryForObject(countSql, Long.class, params.toArray());
long totalCount = total == null ? 0L : total;
int offset = Math.max((pageNo - 1) * pageSize, 0);
String pageSql = groupedSql + buildOrderBy(groupedByMachine) + " LIMIT ? OFFSET ?";
List<Object> pageParams = new ArrayList<>(params);
pageParams.add(pageSize);
pageParams.add(offset);
List<MesXslSmallMaterialDemandPlanSummary> rows = queryRows(pageSql, pageParams, groupedByMachine);
Page<MesXslSmallMaterialDemandPlanSummary> page = new Page<>(pageNo, pageSize, totalCount);
page.setRecords(rows);
return Result.OK(page);
}
@RequiresPermissions("xslmes:mes_xsl_manual_small_material_demand_plan:exportXls")
@RequestMapping("/exportXls")
public ModelAndView exportXls(
HttpServletRequest request,
MesXslSmallMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params) + buildOrderBy(groupedByMachine);
List<MesXslSmallMaterialDemandPlanSummary> exportList = queryRows(groupedSql, params, groupedByMachine);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "人工小料需求计划");
mv.addObject(NormalExcelConstants.CLASS, MesXslSmallMaterialDemandPlanSummary.class);
mv.addObject(
NormalExcelConstants.PARAMS,
new ExportParams(
"人工小料需求计划",
"导出人:" + (sysUser == null ? "admin" : sysUser.getRealname()),
"人工小料需求计划",
ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if (oConvertUtils.isNotEmpty(exportFields)) {
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
private String buildGroupedSql(
MesXslSmallMaterialDemandPlanSummary query, boolean groupedByMachine, List<Object> params) {
String machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
String statDateExpr = "DATE_FORMAT(t.stat_date, '%Y-%m-%d')";
StringBuilder sql = new StringBuilder();
sql.append("SELECT ");
if (groupedByMachine) {
sql.append(machineExpr).append(" AS machineName, ");
} else {
sql.append("'' AS machineName, ");
}
sql.append(rawMaterialExpr)
.append(" AS rawMaterialName, ")
.append("SUM(COALESCE(t.demand_weight,0)) AS demandWeight, ")
.append("MAX(")
.append(statDateExpr)
.append(") AS statDate ")
.append("FROM ")
.append(TABLE_NAME)
.append(" t ")
.append("WHERE (t.del_flag = 0 OR t.del_flag IS NULL) ");
if (query != null && StringUtils.isNotBlank(query.getStatDate())) {
sql.append("AND ").append(statDateExpr).append(" = ? ");
params.add(query.getStatDate().trim());
}
if (query != null && StringUtils.isNotBlank(query.getRawMaterialName())) {
sql.append("AND ").append(rawMaterialExpr).append(" LIKE ? ");
params.add("%" + query.getRawMaterialName().trim() + "%");
}
if (groupedByMachine && query != null && StringUtils.isNotBlank(query.getMachineName())) {
sql.append("AND ").append(machineExpr).append(" LIKE ? ");
params.add("%" + query.getMachineName().trim() + "%");
}
sql.append("GROUP BY ");
if (groupedByMachine) {
sql.append(machineExpr).append(", ");
}
sql.append(rawMaterialExpr);
return sql.toString();
}
private List<MesXslSmallMaterialDemandPlanSummary> queryRows(
String sql, List<Object> params, boolean groupedByMachine) {
return jdbcTemplate.query(
sql,
rs -> {
List<MesXslSmallMaterialDemandPlanSummary> list = new ArrayList<>();
int seq = 1;
while (rs.next()) {
MesXslSmallMaterialDemandPlanSummary row = new MesXslSmallMaterialDemandPlanSummary();
row.setMachineName(groupedByMachine ? trim(rs.getString("machineName")) : "");
row.setRawMaterialName(trim(rs.getString("rawMaterialName")));
row.setDemandWeight(rs.getBigDecimal("demandWeight"));
row.setStatDate(trim(rs.getString("statDate")));
row.setId(buildRowId(row, groupedByMachine, seq++));
list.add(row);
}
return list;
},
params.toArray());
}
private String buildOrderBy(boolean groupedByMachine) {
if (groupedByMachine) {
return " ORDER BY machineName, rawMaterialName";
}
return " ORDER BY rawMaterialName";
}
private String buildRowId(MesXslSmallMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
return machine + "_" + StringUtils.defaultString(row.getRawMaterialName()) + "_" + seq;
}
private String trim(String value) {
return value == null ? "" : value.trim();
}
}

View File

@@ -0,0 +1,61 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.xslmes.entity.MesXslManualSmallMaterialPlanMaintain;
import org.jeecg.modules.xslmes.service.IMesXslManualSmallMaterialPlanMaintainService;
import org.jeecg.modules.xslmes.vo.MesXslManualSmallMaterialPlanMaintainSaveAllVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "人工小料计划维护")
@RestController
@RequestMapping("/xslmes/mesXslManualSmallMaterialPlanMaintain")
public class MesXslManualSmallMaterialPlanMaintainController
extends JeecgController<
MesXslManualSmallMaterialPlanMaintain, IMesXslManualSmallMaterialPlanMaintainService> {
private final IMesXslManualSmallMaterialPlanMaintainService service;
public MesXslManualSmallMaterialPlanMaintainController(
IMesXslManualSmallMaterialPlanMaintainService service) {
this.service = service;
}
@Operation(summary = "人工小料计划维护-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslManualSmallMaterialPlanMaintain>> queryPageList(
MesXslManualSmallMaterialPlanMaintain model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "50") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslManualSmallMaterialPlanMaintain> queryWrapper =
QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.orderByAsc("sort_no").orderByAsc("create_time");
IPage<MesXslManualSmallMaterialPlanMaintain> pageList =
service.page(new Page<>(pageNo, pageSize), queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "人工小料计划维护-整表保存")
@Operation(summary = "人工小料计划维护-整表保存")
@RequiresPermissions("xslmes:mes_xsl_manual_small_material_plan_maintain:saveAll")
@PostMapping("/saveAll")
public Result<String> saveAll(@RequestBody MesXslManualSmallMaterialPlanMaintainSaveAllVO req) {
service.saveAllRows(req == null ? null : req.getRows());
return Result.OK("保存成功");
}
}

View File

@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslManufacturer;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslManufacturerService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
@@ -45,6 +46,9 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
@Autowired
private IMesXslManufacturerService mesXslManufacturerService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES厂家信息-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslManufacturer>> queryPageList(
@@ -93,6 +97,10 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
@RequiresPermissions("mes:mes_xsl_manufacturer:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateManufacturerDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslManufacturerService.removeById(id);
return Result.OK("删除成功!");
}
@@ -102,6 +110,10 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
@RequiresPermissions("mes:mes_xsl_manufacturer:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateManufacturerDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslManufacturerService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -112,13 +112,14 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
@Operation(summary = "校验动作名称是否重复")
@GetMapping("/checkActionName")
public Result<String> checkActionName(
@RequestParam(name = "equipmentId", required = false) String equipmentId,
@RequestParam(name = "actionName", required = true) String actionName,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(actionName) || actionName.trim().isEmpty()) {
return Result.OK("该值可用!");
}
if (mesXslMixerActionService.isActionNameDuplicated(actionName, dataId)) {
return Result.error("动作名称不能重复");
if (mesXslMixerActionService.isActionNameDuplicated(equipmentId, actionName, dataId)) {
return Result.error("同一设备下动作名称不能重复");
}
return Result.OK("该值可用!");
}
@@ -126,13 +127,14 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
@Operation(summary = "校验动作代号是否重复")
@GetMapping("/checkActionCode")
public Result<String> checkActionCode(
@RequestParam(name = "equipmentId", required = false) String equipmentId,
@RequestParam(name = "actionCode", required = true) String actionCode,
@RequestParam(name = "dataId", required = false) String dataId) {
if (oConvertUtils.isEmpty(actionCode) || actionCode.trim().isEmpty()) {
return Result.OK("该值可用!");
}
if (mesXslMixerActionService.isActionCodeDuplicated(actionCode, dataId)) {
return Result.error("动作代号不能重复");
if (mesXslMixerActionService.isActionCodeDuplicated(equipmentId, actionCode, dataId)) {
return Result.error("同一设备下动作代号不能重复");
}
return Result.OK("该值可用!");
}
@@ -152,15 +154,15 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
return "动作名称不能为空";
}
model.setActionName(model.getActionName().trim());
if (mesXslMixerActionService.isActionNameDuplicated(model.getActionName(), excludeId)) {
return "动作名称不能重复";
if (mesXslMixerActionService.isActionNameDuplicated(model.getEquipmentId(), model.getActionName(), excludeId)) {
return "同一设备下动作名称不能重复";
}
if (oConvertUtils.isEmpty(model.getActionCode()) || StringUtils.isBlank(model.getActionCode())) {
return "动作代号不能为空";
}
model.setActionCode(model.getActionCode().trim());
if (mesXslMixerActionService.isActionCodeDuplicated(model.getActionCode(), excludeId)) {
return "动作代号不能重复";
if (mesXslMixerActionService.isActionCodeDuplicated(model.getEquipmentId(), model.getActionCode(), excludeId)) {
return "同一设备下动作代号不能重复";
}
return null;
}

View File

@@ -0,0 +1,81 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.xslmes.entity.MesXslMixingProductionPlan;
import org.jeecg.modules.xslmes.service.IMesXslMixingProductionPlanService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.jeecg.modules.xslmes.vo.MesXslMixingProductionPlanOrderOptionVO;
import org.jeecg.modules.xslmes.vo.MesXslMixingProductionPlanSaveAllVO;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Tag(name = "密炼生产计划维护")
@RestController
@RequestMapping("/xslmes/mesXslMixingProductionPlan")
public class MesXslMixingProductionPlanController
extends JeecgController<MesXslMixingProductionPlan, IMesXslMixingProductionPlanService> {
private final IMesXslMixingProductionPlanService mixingProductionPlanService;
private final MesXslStompNotifyService stompNotify;
public MesXslMixingProductionPlanController(
IMesXslMixingProductionPlanService mixingProductionPlanService,
MesXslStompNotifyService stompNotify) {
this.mixingProductionPlanService = mixingProductionPlanService;
this.stompNotify = stompNotify;
}
@Operation(summary = "密炼生产计划维护-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslMixingProductionPlan>> queryPageList(
MesXslMixingProductionPlan model,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "20") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslMixingProductionPlan> queryWrapper =
QueryGenerator.initQueryWrapper(model, req.getParameterMap());
queryWrapper.orderByAsc("sort_no").orderByAsc("create_time");
IPage<MesXslMixingProductionPlan> pageList =
mixingProductionPlanService.page(new Page<>(pageNo, pageSize), queryWrapper);
return Result.OK(pageList);
}
@AutoLog(value = "密炼生产计划维护-整表保存")
@Operation(summary = "密炼生产计划维护-整表保存")
@RequiresPermissions("xslmes:mes_xsl_mixing_production_plan:saveAll")
@PostMapping("/saveAll")
public Result<String> saveAll(@RequestBody MesXslMixingProductionPlanSaveAllVO req) {
mixingProductionPlanService.saveAllRows(req == null ? null : req.getRows());
//update-begin---author:jiangxh ---date:20260617 for【密炼计划】整表保存后广播桌面端同步-----------
stompNotify.publishMixingProductionPlanChanged("saveAll", null);
//update-end---author:jiangxh ---date:20260617 for【密炼计划】整表保存后广播桌面端同步-----------
return Result.OK("保存成功");
}
@Operation(summary = "密炼生产计划维护-班次生产订单候选分页")
@GetMapping("/orderOptionPage")
public Result<IPage<MesXslMixingProductionPlanOrderOptionVO>> orderOptionPage(
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "keyword", required = false) String keyword,
@RequestParam(name = "machineId", required = false) String machineId,
@RequestParam(name = "machineName", required = false) String machineName) {
return Result.OK(
mixingProductionPlanService.queryOrderOptions(
pageNo, pageSize, keyword, machineId, machineName));
}
}

View File

@@ -20,6 +20,7 @@ import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecSmallWeighRangeVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@@ -175,6 +176,17 @@ public class MesXslMixingSpecController extends JeecgController<MesXslMixingSpec
return Result.OK(mesXslMixingSpecService.queryPurposeOptions(keyword));
}
//update-begin---author:cursor ---date:20260612 for【XSLMES-20260612-A02】混炼示方小料称重范围设置-----------
@AutoLog(value = "MES混炼示方-小料称重范围设置")
@Operation(summary = "MES混炼示方-小料称重范围设置")
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:edit")
@PostMapping(value = "/updateSmallWeighRange")
public Result<String> updateSmallWeighRange(@RequestBody MesXslMixingSpecSmallWeighRangeVO vo) {
mesXslMixingSpecService.updateSmallWeighRange(vo);
return Result.OK("保存成功");
}
//update-end---author:cursor ---date:20260612 for【XSLMES-20260612-A02】混炼示方小料称重范围设置-----------
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, MesXslMixingSpec model) {

View File

@@ -0,0 +1,49 @@
package org.jeecg.modules.xslmes.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecHistory;
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecHistoryService;
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
* 混炼示方历史记录
*/
@Tag(name = "MES混炼示方历史记录")
@RestController
@RequestMapping("/xslmes/mesXslMixingSpecHistory")
@Slf4j
public class MesXslMixingSpecHistoryController {
@Autowired
private IMesXslMixingSpecHistoryService mesXslMixingSpecHistoryService;
@Operation(summary = "混炼示方历史记录-按示方ID查询")
@GetMapping(value = "/listByMixingSpecId")
public Result<List<MesXslMixingSpecHistory>> listByMixingSpecId(
@RequestParam(name = "mixingSpecId", required = true) String mixingSpecId) {
if (StringUtils.isBlank(mixingSpecId)) {
return Result.error("mixingSpecId不能为空");
}
return Result.OK(mesXslMixingSpecHistoryService.listByMixingSpecId(mixingSpecId));
}
@Operation(summary = "混炼示方历史记录-查询快照详情")
@GetMapping(value = "/queryById")
public Result<MesXslMixingSpecPage> queryById(@RequestParam(name = "id", required = true) String id) {
MesXslMixingSpecPage page = mesXslMixingSpecHistoryService.queryPageByHistoryId(id);
if (page == null) {
return Result.error("未找到对应历史记录");
}
return Result.OK(page);
}
}

View File

@@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.List;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.AutoLog;
@@ -97,9 +98,19 @@ public class MesXslProductionOrderController
@Operation(summary = "生产订单-拆分生成母胶计划")
@RequiresPermissions("xslmes:mes_xsl_production_order:split")
@PostMapping("/split")
public Result<MesXslMasterBatchPlan> split(@RequestParam(name = "id", required = true) String id) {
MesXslMasterBatchPlan plan = mesXslProductionOrderService.splitToMasterBatchPlan(id);
return Result.OK("拆分成功", plan);
public Result<List<MesXslMasterBatchPlan>> split(@RequestParam(name = "id", required = true) String id) {
List<MesXslMasterBatchPlan> plans = mesXslProductionOrderService.splitToMasterBatchPlan(id);
return Result.OK("拆分成功", plans);
}
@AutoLog(value = "生产订单-批量拆分生成计划")
@Operation(summary = "生产订单-批量拆分生成计划")
@RequiresPermissions("xslmes:mes_xsl_production_order:split")
@PostMapping("/splitBatch")
public Result<Integer> splitBatch(@RequestParam(name = "ids", required = true) String ids) {
List<String> idList = Arrays.asList(ids.split(","));
int count = mesXslProductionOrderService.splitToMasterBatchPlanBatch(idList);
return Result.OK("批量拆分成功", count);
}
@RequiresPermissions("xslmes:mes_xsl_production_order:exportXls")

View File

@@ -0,0 +1,195 @@
package org.jeecg.modules.xslmes.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslRawMaterialDemandPlanSummary;
import org.jeecgframework.poi.excel.def.NormalExcelConstants;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
/**
* 原材料需求计划(汇总查询)
*/
@Tag(name = "原材料需求计划")
@RestController
@RequestMapping("/xslmes/mesXslRawMaterialDemandPlan")
public class MesXslRawMaterialDemandPlanController {
@Autowired private JdbcTemplate jdbcTemplate;
@Operation(summary = "原材料需求计划-分页列表查询")
@GetMapping("/list")
public Result<IPage<MesXslRawMaterialDemandPlanSummary>> queryPageList(
MesXslRawMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params);
String countSql = "SELECT COUNT(1) FROM (" + groupedSql + ") t";
Long total = jdbcTemplate.queryForObject(countSql, Long.class, params.toArray());
long totalCount = total == null ? 0L : total;
int offset = Math.max((pageNo - 1) * pageSize, 0);
String pageSql = groupedSql + buildOrderBy(groupedByMachine) + " LIMIT ? OFFSET ?";
List<Object> pageParams = new ArrayList<>(params);
pageParams.add(pageSize);
pageParams.add(offset);
List<MesXslRawMaterialDemandPlanSummary> rows = queryRows(pageSql, pageParams, groupedByMachine);
Page<MesXslRawMaterialDemandPlanSummary> page = new Page<>(pageNo, pageSize, totalCount);
page.setRecords(rows);
return Result.OK(page);
}
@RequiresPermissions("xslmes:mes_xsl_raw_material_demand_plan:exportXls")
@RequestMapping("/exportXls")
public ModelAndView exportXls(
HttpServletRequest request,
MesXslRawMaterialDemandPlanSummary query,
@RequestParam(name = "groupByMachine", required = false, defaultValue = "0") Integer groupByMachine) {
boolean groupedByMachine = groupByMachine != null && groupByMachine == 1;
List<Object> params = new ArrayList<>();
String groupedSql = buildGroupedSql(query, groupedByMachine, params) + buildOrderBy(groupedByMachine);
List<MesXslRawMaterialDemandPlanSummary> exportList = queryRows(groupedSql, params, groupedByMachine);
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
mv.addObject(NormalExcelConstants.FILE_NAME, "原材料需求计划");
mv.addObject(NormalExcelConstants.CLASS, MesXslRawMaterialDemandPlanSummary.class);
mv.addObject(
NormalExcelConstants.PARAMS,
new ExportParams(
"原材料需求计划",
"导出人:" + (sysUser == null ? "admin" : sysUser.getRealname()),
"原材料需求计划",
ExcelType.XSSF));
mv.addObject(NormalExcelConstants.DATA_LIST, exportList);
String exportFields = request.getParameter(NormalExcelConstants.EXPORT_FIELDS);
if (oConvertUtils.isNotEmpty(exportFields)) {
mv.addObject(NormalExcelConstants.EXPORT_FIELDS, exportFields);
}
return mv;
}
private String buildGroupedSql(
MesXslRawMaterialDemandPlanSummary query, boolean groupedByMachine, List<Object> params) {
String planDateExpr = "DATE(t.plan_date)";
String machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
String materialIdExpr = "COALESCE(NULLIF(TRIM(t.material_id),''), '')";
String erpCodeExpr = "COALESCE(NULLIF(TRIM(t.erp_code),''), '')";
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
StringBuilder sql = new StringBuilder();
sql.append("SELECT ");
sql.append(planDateExpr).append(" AS planDate, ");
if (groupedByMachine) {
sql.append(machineExpr).append(" AS machineName, ");
} else {
sql.append("'' AS machineName, ");
}
sql.append(materialIdExpr)
.append(" AS materialId, ")
.append(erpCodeExpr)
.append(" AS erpCode, ")
.append(rawMaterialExpr)
.append(" AS rawMaterialName, ")
.append("SUM(COALESCE(t.demand_weight,0)) AS demandWeight, ")
.append("SUM(COALESCE(t.standard_weight,0)) AS standardWeight, ")
.append("SUM(COALESCE(t.actual_weight,0)) AS actualWeight ")
.append("FROM mes_xsl_raw_material_demand_plan t ")
.append("WHERE (t.del_flag = 0 OR t.del_flag IS NULL) ");
if (query != null && StringUtils.isNotBlank(query.getErpCode())) {
sql.append("AND ").append(erpCodeExpr).append(" LIKE ? ");
params.add("%" + query.getErpCode().trim() + "%");
}
if (query != null && StringUtils.isNotBlank(query.getRawMaterialName())) {
sql.append("AND ").append(rawMaterialExpr).append(" LIKE ? ");
params.add("%" + query.getRawMaterialName().trim() + "%");
}
if (groupedByMachine && query != null && StringUtils.isNotBlank(query.getMachineName())) {
sql.append("AND ").append(machineExpr).append(" LIKE ? ");
params.add("%" + query.getMachineName().trim() + "%");
}
if (query != null && query.getPlanDate() != null) {
sql.append("AND ").append(planDateExpr).append(" = ? ");
params.add(new java.sql.Date(query.getPlanDate().getTime()));
}
sql.append("GROUP BY ").append(planDateExpr).append(", ");
if (groupedByMachine) {
sql.append(machineExpr).append(", ");
}
sql.append(materialIdExpr).append(", ").append(erpCodeExpr).append(", ").append(rawMaterialExpr);
return sql.toString();
}
private List<MesXslRawMaterialDemandPlanSummary> queryRows(
String sql, List<Object> params, boolean groupedByMachine) {
return jdbcTemplate.query(
sql,
rs -> {
List<MesXslRawMaterialDemandPlanSummary> list = new ArrayList<>();
int seq = 1;
while (rs.next()) {
MesXslRawMaterialDemandPlanSummary row = new MesXslRawMaterialDemandPlanSummary();
row.setPlanDate(rs.getDate("planDate"));
row.setMachineName(groupedByMachine ? trim(rs.getString("machineName")) : "");
row.setMaterialId(trim(rs.getString("materialId")));
row.setErpCode(trim(rs.getString("erpCode")));
row.setRawMaterialName(trim(rs.getString("rawMaterialName")));
row.setDemandWeight(rs.getBigDecimal("demandWeight"));
row.setStandardWeight(rs.getBigDecimal("standardWeight"));
row.setActualWeight(rs.getBigDecimal("actualWeight"));
row.setId(buildRowId(row, groupedByMachine, seq++));
list.add(row);
}
return list;
},
params.toArray());
}
private String buildOrderBy(boolean groupedByMachine) {
if (groupedByMachine) {
return " ORDER BY planDate DESC, machineName, rawMaterialName, erpCode";
}
return " ORDER BY planDate DESC, rawMaterialName, erpCode";
}
private String buildRowId(MesXslRawMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
return String.valueOf(row.getPlanDate())
+ "_"
+ machine
+ "_"
+ StringUtils.defaultString(row.getMaterialId())
+ "_"
+ seq;
}
private String trim(String value) {
return value == null ? "" : value.trim();
}
}

View File

@@ -25,6 +25,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestDataPoint;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestDataPointService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
@@ -51,6 +52,9 @@ public class MesXslRubberQuickTestDataPointController
@Autowired
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES胶料快检数据点-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslRubberQuickTestDataPoint>> queryPageList(
@@ -120,6 +124,10 @@ public class MesXslRubberQuickTestDataPointController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestDataPointDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestDataPointService.removeById(id);
return Result.OK("删除成功!");
}
@@ -129,6 +137,10 @@ public class MesXslRubberQuickTestDataPointController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestDataPointDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestDataPointService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -50,6 +50,7 @@ import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestDataPointService;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
@@ -102,7 +103,8 @@ public class MesXslRubberQuickTestMethodController
private IMesXslRubberQuickTestDataPointService mesXslRubberQuickTestDataPointService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES胶料快检实验方法-分页列表查询")
@@ -231,29 +233,25 @@ public class MesXslRubberQuickTestMethodController
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestMethodDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestMethodService.delMain(id);
return Result.OK("删除成功!");
}
@AutoLog(value = "MES胶料快检实验方法-批量删除")
@Operation(summary = "MES胶料快检实验方法-批量删除")
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_method:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestMethodDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestMethodService.delBatchMain(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -16,10 +16,17 @@ import org.jeecg.common.aspect.annotation.AutoLog;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.common.system.vo.LoginUser;
import org.apache.shiro.SecurityUtils;
import org.jeecg.modules.mes.material.entity.MesMaterial;
import org.jeecg.modules.mes.material.service.IMesMaterialService;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecord;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
@@ -27,6 +34,7 @@ import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordBatchFromMaterialV
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestRecordPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@@ -49,6 +57,9 @@ public class MesXslRubberQuickTestRecordController
@Autowired
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
@Autowired
private ISysUserService sysUserService;
@Operation(summary = "MES胶料快检记录-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslRubberQuickTestRecord>> queryPageList(
@@ -109,13 +120,9 @@ public class MesXslRubberQuickTestRecordController
@RequiresPermissions("mes:mes_material:rubberQuickTestInspect")
@PostMapping(value = "/batchFromMaterial")
public Result<List<String>> batchFromMaterial(@RequestBody MesXslRubberQuickTestRecordBatchFromMaterialVO vo) {
try {
List<String> ids = mesXslRubberQuickTestRecordService.batchFromMaterial(vo);
return Result.OK("成功生成 " + ids.size() + " 条快检记录", ids);
} catch (Exception e) {
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
//update-begin---author:jiangxh ---date:2026-06-22 for【快检记录】取消胶料列表批量生成改由桌面端同步-----------
return Result.error("该功能已停用,请通过桌面端新增并同步胶料快检记录");
//update-end---author:jiangxh ---date:2026-06-22 for【快检记录】取消胶料列表批量生成改由桌面端同步-----------
}
@AutoLog(value = "MES胶料快检记录-删除")
@@ -143,6 +150,12 @@ public class MesXslRubberQuickTestRecordController
if (entity == null) {
return Result.error("未找到对应数据");
}
//update-begin---author:jiangxh ---date:2026-06-22 for【快检记录】查询含数据标准/试验结果/曲线图明细-----------
entity.setStdLineList(mesXslRubberQuickTestRecordService.selectStdLinesByRecordId(id));
entity.setRawLineList(mesXslRubberQuickTestRecordService.selectRawLinesByRecordId(id));
entity.setChartPointList(mesXslRubberQuickTestRecordService.selectChartPointsByRecordId(id));
entity.setLineList(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id));
//update-end---author:jiangxh ---date:2026-06-22 for【快检记录】查询含数据标准/试验结果/曲线图明细-----------
return Result.OK(entity);
}
@@ -153,6 +166,31 @@ public class MesXslRubberQuickTestRecordController
return Result.OK(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id));
}
//update-begin---author:jiangxh ---date:2026-06-17 for【快检记录】查询原始数据明细-----------
@Operation(summary = "MES胶料快检记录-查询原始数据明细")
@GetMapping(value = "/queryRawLineListByRecordId")
public Result<List<MesXslRubberQuickTestRecordRawLine>> queryRawLineListByRecordId(
@RequestParam(name = "id", required = true) String id) {
return Result.OK(mesXslRubberQuickTestRecordService.selectRawLinesByRecordId(id));
}
//update-end---author:jiangxh ---date:2026-06-17 for【快检记录】查询原始数据明细-----------
//update-begin---author:jiangxh ---date:2026-06-22 for【快检记录】查询数据标准明细与曲线图-----------
@Operation(summary = "MES胶料快检记录-查询数据标准明细")
@GetMapping(value = "/queryStdLineListByRecordId")
public Result<List<MesXslRubberQuickTestRecordStdLine>> queryStdLineListByRecordId(
@RequestParam(name = "id", required = true) String id) {
return Result.OK(mesXslRubberQuickTestRecordService.selectStdLinesByRecordId(id));
}
@Operation(summary = "MES胶料快检记录-查询曲线图数据点")
@GetMapping(value = "/queryChartPointListByRecordId")
public Result<List<MesXslRubberQuickTestRecordChartPoint>> queryChartPointListByRecordId(
@RequestParam(name = "id", required = true) String id) {
return Result.OK(mesXslRubberQuickTestRecordService.selectChartPointsByRecordId(id));
}
//update-end---author:jiangxh ---date:2026-06-22 for【快检记录】查询数据标准明细与曲线图-----------
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) {
@@ -169,14 +207,22 @@ public class MesXslRubberQuickTestRecordController
if (main == null) {
return "参数不能为空";
}
if (oConvertUtils.isEmpty(main.getRubberMaterialId())) {
return "请选择胶料";
//update-begin---author:jiangxh ---date:2026-06-22 for【快检记录】Web保存校验支持桌面端三类明细-----------
if (oConvertUtils.isNotEmpty(main.getRubberMaterialId())) {
MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId());
if (material == null) {
return "所选胶料不存在";
}
main.setRubberMaterialName(material.getMaterialName());
} else if (oConvertUtils.isEmpty(main.getRubberMaterialName())) {
return "胶料名称不能为空";
}
MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId());
if (material == null) {
return "所选胶料不存在";
if (!CollectionUtils.isEmpty(main.getStdLineList()) && !CollectionUtils.isEmpty(main.getRawLineList())) {
resolveInspector(main);
return null;
}
main.setRubberMaterialName(material.getMaterialName());
//update-end---author:jiangxh ---date:2026-06-22 for【快检记录】Web保存校验支持桌面端三类明细-----------
if (oConvertUtils.isNotEmpty(main.getQuickTestTypeId())) {
MesXslRubberQuickTestType type = mesXslRubberQuickTestTypeService.getById(main.getQuickTestTypeId());
@@ -186,6 +232,10 @@ public class MesXslRubberQuickTestRecordController
main.setQuickTestTypeName(type.getTypeName());
}
//update-begin---author:jiangxh ---date:20260616 for【MES】胶料快检记录保存时补全检验人姓名冗余-----------
resolveInspector(main);
//update-end---author:jiangxh ---date:20260616 for【MES】胶料快检记录保存时补全检验人姓名冗余-----------
if (lineList == null || lineList.isEmpty()) {
return "请维护检验明细";
}
@@ -197,4 +247,35 @@ public class MesXslRubberQuickTestRecordController
}
return null;
}
//update-begin---author:jiangxh ---date:20260616 for【MES】胶料快检记录检验人冗余字段补全-----------
private void resolveInspector(MesXslRubberQuickTestRecord main) {
if (main == null || oConvertUtils.isEmpty(main.getInspectorUserId())) {
return;
}
if (oConvertUtils.isNotEmpty(main.getInspectorRealname())) {
return;
}
SysUser user = sysUserService.getById(main.getInspectorUserId().trim());
if (user != null) {
main.setInspectorUsername(user.getUsername());
main.setInspectorRealname(user.getRealname());
}
}
private void fillInspectorIfEmpty(MesXslRubberQuickTestRecordBatchFromMaterialVO vo) {
if (vo == null || oConvertUtils.isNotEmpty(vo.getInspectorUserId())) {
return;
}
if (SecurityUtils.getSubject() == null || SecurityUtils.getSubject().getPrincipal() == null) {
return;
}
if (!(SecurityUtils.getSubject().getPrincipal() instanceof LoginUser user)) {
return;
}
vo.setInspectorUserId(user.getId());
vo.setInspectorUsername(user.getUsername());
vo.setInspectorRealname(user.getRealname());
}
//update-end---author:jiangxh ---date:20260616 for【MES】胶料快检记录检验人冗余字段补全-----------
}

View File

@@ -34,7 +34,9 @@ import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -69,6 +71,12 @@ public class MesXslRubberQuickTestStdController
@Autowired
private ISysDepartService sysDepartService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Autowired
private MesXslStompNotifyService stompNotify;
@Operation(summary = "MES胶料快检实验标准-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslRubberQuickTestStd>> queryPageList(
@@ -103,6 +111,9 @@ public class MesXslRubberQuickTestStdController
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("add", main.getId());
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("添加成功!");
}
@@ -125,6 +136,9 @@ public class MesXslRubberQuickTestStdController
log.error(e.getMessage(), e);
return Result.error(e.getMessage());
}
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("edit", main.getId());
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("编辑成功!");
}
@@ -133,7 +147,14 @@ public class MesXslRubberQuickTestStdController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestStdDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestStdService.delMain(id);
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("delete", id);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("删除成功!");
}
@@ -142,7 +163,14 @@ public class MesXslRubberQuickTestStdController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestStdDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestStdService.delBatchMain(Arrays.asList(ids.split(",")));
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("batchDelete", ids);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("批量删除成功!");
}
@@ -184,6 +212,9 @@ public class MesXslRubberQuickTestStdController
.set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus)
.update();
if (updated) {
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
stompNotify.publishRubberQuickTestStdChanged("status", id);
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】桌面端 STOMP 同步-----------
return Result.OK("操作成功");
}
MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id);
@@ -226,13 +257,6 @@ public class MesXslRubberQuickTestStdController
if (main == null) {
return "参数不能为空";
}
if (oConvertUtils.isEmpty(main.getStdName())) {
return "实验标准名称不能为空";
}
main.setStdName(main.getStdName().trim());
if (mesXslRubberQuickTestStdService.isStdNameDuplicated(main.getStdName(), excludeId, main)) {
return "实验标准名称已存在";
}
if (oConvertUtils.isEmpty(main.getTestMethodId())) {
return "请选择实验方法";
}
@@ -242,13 +266,22 @@ public class MesXslRubberQuickTestStdController
}
main.setTestMethodName(method.getMethodName());
if (oConvertUtils.isNotEmpty(main.getRubberMaterialId())) {
MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId());
if (material == null) {
return "所选胶料不存在";
}
main.setRubberMaterialName(material.getMaterialName());
if (oConvertUtils.isEmpty(main.getRubberMaterialId())) {
return "请选择胶料信息";
}
MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId());
if (material == null) {
return "所选胶料不存在";
}
main.setRubberMaterialName(material.getMaterialName());
//update-begin---author:jiangxh ---date:20260616 for【MES】胶料快检实验标准名称自动生成实验方法名称_胶料名称-----------
String stdName = main.getTestMethodName().trim() + "_" + main.getRubberMaterialName().trim();
main.setStdName(stdName);
if (mesXslRubberQuickTestStdService.isStdNameDuplicated(stdName, excludeId, main)) {
return "实验标准名称已存在";
}
//update-end---author:jiangxh ---date:20260616 for【MES】胶料快检实验标准名称自动生成实验方法名称_胶料名称-----------
if (oConvertUtils.isNotEmpty(main.getPsCompileId())) {
MesXslMixerPsCompile ps = mesXslMixerPsCompileService.getById(main.getPsCompileId());
@@ -258,6 +291,18 @@ public class MesXslRubberQuickTestStdController
if (!XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(ps.getPsType())) {
return "发行编号须选择类型为原材料检验标准的密炼PS";
}
//update-begin---author:jiangxh ---date:20260617 for【快检实验标准】发行编号仅允许选择编制状态密炼PS-----------
boolean psCompileIdChanged = true;
if (oConvertUtils.isNotEmpty(excludeId)) {
MesXslRubberQuickTestStd existingStd = mesXslRubberQuickTestStdService.getById(excludeId);
if (existingStd != null && oConvertUtils.isNotEmpty(existingStd.getPsCompileId())) {
psCompileIdChanged = !existingStd.getPsCompileId().equals(main.getPsCompileId());
}
}
if (psCompileIdChanged && !"compile".equals(ps.getStatus())) {
return "发行编号须选择编制状态的密炼PS";
}
//update-end---author:jiangxh ---date:20260617 for【快检实验标准】发行编号仅允许选择编制状态密炼PS-----------
main.setIssueNumber(ps.getPsCode());
if (main.getIssueDate() == null && ps.getIssueDate() != null) {
main.setIssueDate(ps.getIssueDate());

View File

@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
@@ -44,6 +45,9 @@ public class MesXslRubberQuickTestTypeController
@Autowired
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES胶料快检实验类型-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslRubberQuickTestType>> queryPageList(
@@ -116,6 +120,10 @@ public class MesXslRubberQuickTestTypeController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestTypeDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestTypeService.removeById(id);
return Result.OK("删除成功!");
}
@@ -125,6 +133,10 @@ public class MesXslRubberQuickTestTypeController
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateRubberQuickTestTypeDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberQuickTestTypeService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslRubberSmallLockReason;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslRubberSmallLockReasonService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
@@ -44,6 +45,9 @@ public class MesXslRubberSmallLockReasonController
@Autowired
private IMesXslRubberSmallLockReasonService mesXslRubberSmallLockReasonService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES胶料小料锁定原因-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslRubberSmallLockReason>> queryPageList(
@@ -122,6 +126,10 @@ public class MesXslRubberSmallLockReasonController
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateRubberSmallLockReasonDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberSmallLockReasonService.removeById(id);
return Result.OK("删除成功!");
}
@@ -131,6 +139,10 @@ public class MesXslRubberSmallLockReasonController
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateRubberSmallLockReasonDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslRubberSmallLockReasonService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.entity.MesXslSparePartsCategory;
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
import org.jeecg.modules.xslmes.service.IMesXslSparePartsCategoryService;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
@@ -42,6 +43,9 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
@Autowired
private IMesXslSparePartsCategoryService mesXslSparePartsCategoryService;
@Autowired
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
@Operation(summary = "MES备品件类别-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<MesXslSparePartsCategory>> queryPageList(
@@ -90,6 +94,10 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
@RequiresPermissions("mes:mes_xsl_spare_parts_category:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
String refErr = mesXslDeleteReferenceService.validateSparePartsCategoryDelete(List.of(id));
if (refErr != null) {
return Result.error(refErr);
}
mesXslSparePartsCategoryService.removeById(id);
return Result.OK("删除成功!");
}
@@ -99,6 +107,10 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
@RequiresPermissions("mes:mes_xsl_spare_parts_category:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
String refErr = mesXslDeleteReferenceService.validateSparePartsCategoryDelete(Arrays.asList(ids.split(",")));
if (refErr != null) {
return Result.error(refErr);
}
mesXslSparePartsCategoryService.removeByIds(Arrays.asList(ids.split(",")));
return Result.OK("批量删除成功!");
}

View File

@@ -3,6 +3,7 @@ package org.jeecg.modules.xslmes.dingtalk.service;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.print.vo.PrintBizFieldItemVO;
import org.jeecg.modules.system.service.ISysDictService;
import org.springframework.beans.factory.annotation.Autowired;
@@ -79,7 +80,7 @@ public class DingTplBindFieldValueResolver {
return null;
}
if (cur instanceof Map) {
cur = ((Map<String, Object>) cur).get(p);
cur = getMapValue((Map<String, Object>) cur, p);
} else {
return null;
}
@@ -87,6 +88,32 @@ public class DingTplBindFieldValueResolver {
return cur;
}
/** JDBC 行多为下划线列名,绑定配置为驼峰字段名,双向兼容取值 */
@SuppressWarnings("unchecked")
private Object getMapValue(Map<String, Object> map, String key) {
if (map == null || StringUtils.isBlank(key)) {
return null;
}
Object val = map.get(key);
if (val != null) {
return val;
}
String underline = oConvertUtils.camelToUnderline(key);
if (!underline.equals(key)) {
val = map.get(underline);
if (val != null) {
return val;
}
}
if (key.contains("_")) {
String camel = oConvertUtils.camelName(key);
if (!camel.equals(key)) {
val = map.get(camel);
}
}
return val;
}
@SuppressWarnings("unchecked")
private String getDictTextFromRow(Object rowData, String bizField) {
if (!(rowData instanceof Map) || StringUtils.isBlank(bizField)) {
@@ -95,13 +122,13 @@ public class DingTplBindFieldValueResolver {
Map<String, Object> map = (Map<String, Object>) rowData;
String[] parts = bizField.split("\\.");
if (parts.length == 1) {
Object v = map.get(parts[0] + "_dictText");
Object v = getMapValue(map, parts[0] + "_dictText");
return v != null ? String.valueOf(v) : null;
}
String parentPath = String.join(".", java.util.Arrays.copyOf(parts, parts.length - 1));
Object parent = getNestedValue(rowData, parentPath);
if (parent instanceof Map) {
Object v = ((Map<?, ?>) parent).get(parts[parts.length - 1] + "_dictText");
Object v = getMapValue((Map<String, Object>) parent, parts[parts.length - 1] + "_dictText");
return v != null ? String.valueOf(v) : null;
}
return null;

View File

@@ -0,0 +1,339 @@
package org.jeecg.modules.xslmes.dingtalk.service;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.print.catalog.IPrintBizEntityFieldCatalogProvider;
import org.jeecg.modules.print.service.IPrintBizPermEntityService;
import org.jeecg.modules.print.util.PrintBizDetailPropertyScanner;
import org.jeecg.modules.print.util.PrintBizEntityFieldIntrospector;
import org.jeecg.modules.print.vo.PrintBizDetailSlotVO;
import org.jeecg.modules.print.vo.PrintBizFieldItemVO;
import org.jeecg.modules.print.vo.PrintBizTypeVO;
import org.jeecg.modules.xslmes.approval.entity.MesXslApprovalFlow;
import org.jeecg.modules.xslmes.approval.entity.MesXslApprovalInstance;
import org.jeecg.modules.xslmes.dingtalk.entity.MesXslDingProcessTpl;
import org.jeecg.modules.xslmes.dingtalk.entity.MesXslDingTplBind;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
/**
* 按钉钉审批模板绑定配置构建 IM 聊天审批卡片字段,与钉钉发起审批表单展示对齐。
*/
@Slf4j
@Service
public class DingTplImCardBuilder {
private static final Pattern IDENTIFIER = Pattern.compile("^[A-Za-z0-9_]+$");
private static final String CARD_STYLE_DING = "ding";
/** 与前端 dingTplFieldValue.defaultValueMode 一致:下拉类控件默认原值 */
private static final Set<String> DD_SELECT_COMPONENTS = Set.of(
"DDSelectField", "DDMultiSelectField", "DepartmentField", "InnerContactField");
@Autowired
private IMesXslDingTplBindService bindService;
@Autowired
private IMesXslDingProcessTplService tplService;
@Autowired
private DingTplBindFieldValueResolver fieldValueResolver;
@Autowired
private IPrintBizPermEntityService printBizPermEntityService;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired(required = false)
private IPrintBizEntityFieldCatalogProvider fieldCatalogProvider;
/**
* 若存在启用的钉钉模板绑定,则按绑定字段构建完整 biz_record 载荷;否则返回 null 由调用方降级。
*/
public JSONObject buildCardPayload(MesXslApprovalInstance inst, MesXslApprovalFlow flow,
String actionLabel, boolean canApprove, String routePath,
boolean approvalCard) {
if (inst == null || oConvertUtils.isEmpty(routePath)) {
return null;
}
MesXslDingTplBind bind = bindService.resolveActiveByRoutePath(routePath);
if (bind == null || oConvertUtils.isEmpty(bind.getFieldMappingJson())) {
return null;
}
MesXslDingProcessTpl tpl = tplService.getById(bind.getTemplateId());
if (tpl == null || !"1".equals(tpl.getStatus())) {
return null;
}
Map<String, Object> rowData = loadBizRow(inst.getBizTable(), inst.getBizDataId());
if (rowData.isEmpty()) {
return null;
}
Map<String, PrintBizFieldItemVO> metaMap = buildFieldMetaMap(bind.getBizCode());
JSONArray fields = buildDingStyleFields(bind.getFieldMappingJson(), rowData, metaMap);
appendApprovalMetaFields(fields, inst, flow, approvalCard);
JSONObject item = buildItem(inst, routePath, fields, actionLabel, canApprove, approvalCard);
JSONArray items = new JSONArray();
items.add(item);
JSONObject payload = new JSONObject();
payload.put("v", 2);
payload.put("cardStyle", CARD_STYLE_DING);
payload.put("templateId", bind.getTemplateId());
payload.put("templateName", oConvertUtils.getString(bind.getTemplateName(), tpl.getTplName()));
payload.put("pageTitle", oConvertUtils.getString(inst.getBizTableName(), flow != null ? flow.getFlowName() : inst.getFlowName()));
payload.put("pagePath", routePath);
payload.put("rowKey", "id");
payload.put("items", items);
return payload;
}
private JSONArray buildDingStyleFields(String mappingJson, Map<String, Object> rowData,
Map<String, PrintBizFieldItemVO> metaMap) {
JSONArray fields = new JSONArray();
JSONArray mappings;
try {
mappings = JSON.parseArray(mappingJson);
} catch (Exception e) {
log.warn("解析钉钉模板绑定 JSON 失败: {}", e.getMessage());
return fields;
}
if (mappings == null || mappings.isEmpty()) {
return fields;
}
for (int i = 0; i < mappings.size(); i++) {
JSONObject mapping = mappings.getJSONObject(i);
if (mapping == null) {
continue;
}
String componentName = mapping.getString("componentName");
if ("TableField".equals(componentName)) {
continue;
}
String label = mapping.getString("componentLabel");
String bizField = mapping.getString("bizField");
if (oConvertUtils.isEmpty(label) || oConvertUtils.isEmpty(bizField)) {
if ("TextNote".equals(componentName) && oConvertUtils.isNotEmpty(label)) {
addField(fields, label, "");
}
continue;
}
PrintBizFieldItemVO meta = metaMap.get(bizField.trim());
String valueMode = resolveValueMode(mapping, meta);
Object val = fieldValueResolver.resolveValue(rowData, bizField.trim(), valueMode, meta);
addField(fields, label, formatValue(val));
}
return fields;
}
private void appendApprovalMetaFields(JSONArray fields, MesXslApprovalInstance inst,
MesXslApprovalFlow flow, boolean approvalCard) {
addField(fields, "审批流", oConvertUtils.getString(inst.getFlowName(),
flow != null ? flow.getFlowName() : ""));
addField(fields, approvalCard ? "当前节点" : "知会",
oConvertUtils.getString(inst.getCurrentNodeName(), approvalCard ? "审批" : "抄送"));
addField(fields, "状态", statusText(inst.getStatus()));
}
private JSONObject buildItem(MesXslApprovalInstance inst, String routePath, JSONArray fields,
String actionLabel, boolean canApprove, boolean approvalCard) {
JSONObject item = new JSONObject();
item.put("recordId", inst.getBizDataId());
item.put("fields", fields);
StringBuilder body = new StringBuilder();
for (int i = 0; i < fields.size(); i++) {
JSONObject f = fields.getJSONObject(i);
if (i > 0) {
body.append("\n");
}
body.append(f.getString("label")).append(": ").append(f.getString("value"));
}
item.put("body", body.toString());
String sep = routePath.contains("?") ? "&" : "?";
item.put("linkPath", routePath + sep + "imRecordId=" + inst.getBizDataId());
if (approvalCard) {
item.put("instanceId", inst.getId());
item.put("canApprove", canApprove);
item.put("nodeId", inst.getCurrentNodeId());
if (oConvertUtils.isNotEmpty(actionLabel)) {
item.put("actionLabel", actionLabel);
}
}
return item;
}
private Map<String, Object> loadBizRow(String table, String bizDataId) {
if (oConvertUtils.isEmpty(table) || oConvertUtils.isEmpty(bizDataId)
|| !IDENTIFIER.matcher(table).matches()) {
return Collections.emptyMap();
}
try {
List<Map<String, Object>> rows = jdbcTemplate.queryForList(
"SELECT * FROM `" + table + "` WHERE id = ? LIMIT 1", bizDataId);
if (rows.isEmpty()) {
return Collections.emptyMap();
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】JDBC列名下划线转驼峰,与绑定字段对齐-----------
return normalizeRowKeys(rows.get(0));
//update-end---author:GHT ---date:20260610 for【IM审批通用化】JDBC列名下划线转驼峰,与绑定字段对齐-----------
} catch (Exception e) {
log.warn("加载业务单据失败 table={} id={}", table, bizDataId, e);
return Collections.emptyMap();
}
}
private Map<String, Object> normalizeRowKeys(Map<String, Object> raw) {
Map<String, Object> normalized = new LinkedHashMap<>();
if (raw == null) {
return normalized;
}
for (Map.Entry<String, Object> e : raw.entrySet()) {
String key = e.getKey();
if (oConvertUtils.isEmpty(key)) {
continue;
}
normalized.put(key, e.getValue());
if (key.contains("_")) {
String camel = oConvertUtils.camelName(key);
normalized.putIfAbsent(camel, e.getValue());
}
}
return normalized;
}
/** 与钉钉发起弹窗 defaultValueMode 对齐 */
private String resolveValueMode(JSONObject mapping, PrintBizFieldItemVO meta) {
String mode = mapping.getString("valueMode");
if (oConvertUtils.isNotEmpty(mode)) {
return mode.trim();
}
if (meta == null || oConvertUtils.isEmpty(meta.getTranslateKind())
|| "NONE".equalsIgnoreCase(meta.getTranslateKind())) {
return "raw";
}
String componentName = mapping.getString("componentName");
if (oConvertUtils.isNotEmpty(componentName) && DD_SELECT_COMPONENTS.contains(componentName)) {
return "raw";
}
return "text";
}
private Map<String, PrintBizFieldItemVO> buildFieldMetaMap(String bizCode) {
if (oConvertUtils.isEmpty(bizCode)) {
return Collections.emptyMap();
}
Map<String, PrintBizFieldItemVO> map = new LinkedHashMap<>();
for (PrintBizFieldItemVO f : listMainFieldsEnriched(bizCode)) {
if (f != null && StringUtils.isNotBlank(f.getFieldKey())) {
map.put(f.getFieldKey(), f);
}
}
Class<?> mainCls = resolveEntityClass(bizCode);
if (mainCls != null && fieldCatalogProvider != null && fieldCatalogProvider.hasCatalogForBiz(bizCode)) {
for (PrintBizDetailSlotVO slot : fieldCatalogProvider.listDetailSlots(bizCode)) {
mergeDetailMeta(map, bizCode, slot.getPropertyName(), slot.getSlotKind());
}
} else if (mainCls != null) {
for (PrintBizDetailSlotVO slot : PrintBizDetailPropertyScanner.listSlots(mainCls)) {
mergeDetailMeta(map, bizCode, slot.getPropertyName(), slot.getSlotKind());
}
}
return map;
}
private List<PrintBizFieldItemVO> listMainFieldsEnriched(String bizCode) {
Class<?> cls = resolveEntityClass(bizCode);
List<PrintBizFieldItemVO> fields;
if (fieldCatalogProvider != null && fieldCatalogProvider.hasCatalogForBiz(bizCode)) {
fields = fieldCatalogProvider.listMainFields(bizCode);
} else if (cls != null) {
fields = PrintBizEntityFieldIntrospector.listFields(cls);
} else {
return Collections.emptyList();
}
if (cls != null && fields != null && !fields.isEmpty()) {
PrintBizEntityFieldIntrospector.enrichDictMeta(fields, cls, null);
}
return fields != null ? fields : Collections.emptyList();
}
private void mergeDetailMeta(Map<String, PrintBizFieldItemVO> map, String bizCode, String prop, String kind) {
List<PrintBizFieldItemVO> detailFields;
if (fieldCatalogProvider != null && fieldCatalogProvider.hasCatalogForBiz(bizCode)) {
detailFields = fieldCatalogProvider.listPrefixedDetailFields(bizCode, prop, kind);
} else {
Class<?> mainCls = resolveEntityClass(bizCode);
detailFields = mainCls == null
? Collections.emptyList()
: PrintBizDetailPropertyScanner.listPrefixedDetailFields(mainCls, prop, kind);
}
Class<?> itemCls = resolveDetailItemClass(bizCode, prop, kind);
if (itemCls != null && detailFields != null && !detailFields.isEmpty()) {
PrintBizEntityFieldIntrospector.enrichDictMeta(detailFields, itemCls, null);
}
if (detailFields != null) {
for (PrintBizFieldItemVO f : detailFields) {
if (f != null && StringUtils.isNotBlank(f.getFieldKey())) {
map.put(f.getFieldKey(), f);
}
}
}
}
private Class<?> resolveEntityClass(String bizCode) {
PrintBizTypeVO vo = printBizPermEntityService.resolveBizTypeVo(bizCode);
if (vo == null || StringUtils.isBlank(vo.getDescription())) {
return null;
}
return PrintBizEntityFieldIntrospector.tryLoadClass(vo.getDescription().trim());
}
private Class<?> resolveDetailItemClass(String bizCode, String detailProperty, String slotKind) {
Class<?> mainCls = resolveEntityClass(bizCode);
if (mainCls == null) {
return null;
}
return PrintBizDetailPropertyScanner.resolveItemClassForSlot(mainCls, detailProperty, slotKind);
}
private void addField(JSONArray fields, String label, String value) {
JSONObject f = new JSONObject();
f.put("label", label);
f.put("value", oConvertUtils.getString(value, ""));
fields.add(f);
}
private String formatValue(Object val) {
if (val == null) {
return "";
}
if (val instanceof Date) {
return new SimpleDateFormat("yyyy-MM-dd").format((Date) val);
}
return String.valueOf(val);
}
private String statusText(String status) {
if ("1".equals(status)) {
return "已通过";
}
if ("2".equals(status)) {
return "已驳回";
}
if ("3".equals(status)) {
return "已撤销";
}
return "审批中";
}
}

View File

@@ -13,4 +13,7 @@ public interface IMesXslDingTplBindService extends IService<MesXslDingTplBind> {
/** 按业务编码查询绑定记录(未删除的第一条) */
MesXslDingTplBind getByBizCode(String bizCode);
/** 按前端路由解析启用的钉钉模板绑定(模板停用则返回 null */
MesXslDingTplBind resolveActiveByRoutePath(String routePath);
}

View File

@@ -2,11 +2,18 @@ package org.jeecg.modules.xslmes.dingtalk.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.modules.xslmes.dingtalk.entity.MesXslDingProcessTpl;
import org.jeecg.modules.xslmes.dingtalk.entity.MesXslDingTplBind;
import org.jeecg.modules.xslmes.dingtalk.mapper.MesXslDingTplBindMapper;
import org.jeecg.modules.xslmes.dingtalk.service.IMesXslDingProcessTplService;
import org.jeecg.modules.xslmes.dingtalk.service.IMesXslDingTplBindService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 钉钉审批模板绑定 ServiceImpl
*
@@ -17,8 +24,43 @@ import org.springframework.stereotype.Service;
public class MesXslDingTplBindServiceImpl extends ServiceImpl<MesXslDingTplBindMapper, MesXslDingTplBind>
implements IMesXslDingTplBindService {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private IMesXslDingProcessTplService tplService;
@Override
public MesXslDingTplBind getByBizCode(String bizCode) {
return getOne(new QueryWrapper<MesXslDingTplBind>().eq("biz_code", bizCode).last("LIMIT 1"));
}
//update-begin---author:GHT ---date:20260610 for【IM审批通用化】按路由解析启用的钉钉模板绑定-----------
@Override
public MesXslDingTplBind resolveActiveByRoutePath(String routePath) {
if (StringUtils.isBlank(routePath)) {
return null;
}
String path = routePath.trim();
String sql = "SELECT id FROM sys_permission WHERE url = ? AND del_flag = 0 LIMIT 1";
List<String> ids;
try {
ids = jdbcTemplate.queryForList(sql, String.class, path);
} catch (Exception e) {
return null;
}
if (ids.isEmpty()) {
return null;
}
MesXslDingTplBind bind = getByBizCode(ids.get(0));
if (bind == null || StringUtils.isBlank(bind.getTemplateId())) {
return null;
}
MesXslDingProcessTpl tpl = tplService.getById(bind.getTemplateId());
if (tpl == null || !"1".equals(tpl.getStatus())) {
return null;
}
return bind;
}
//update-end---author:GHT ---date:20260610 for【IM审批通用化】按路由解析启用的钉钉模板绑定-----------
}

View File

@@ -0,0 +1,69 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 自动小料计划维护
*/
@Data
@TableName("mes_xsl_auto_small_material_plan_maintain")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "自动小料计划维护")
public class MesXslAutoSmallMaterialPlanMaintain implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "排序号", width = 10)
private Integer sortNo;
@Excel(name = "配方名称", width = 20)
private String formulaName;
@Excel(name = "早班序号", width = 12)
private Integer morningSeqNo;
@Excel(name = "早班计划", width = 12)
private Integer morningPlanCount;
@Excel(name = "早班备注", width = 20)
private String morningRemark;
@Excel(name = "中班序号", width = 12)
private Integer noonSeqNo;
@Excel(name = "中班计划", width = 12)
private Integer noonPlanCount;
@Excel(name = "中班备注", width = 20)
private String noonRemark;
@Excel(name = "夜班序号", width = 12)
private Integer nightSeqNo;
@Excel(name = "夜班计划", width = 12)
private Integer nightPlanCount;
@Excel(name = "夜班备注", width = 20)
private String nightRemark;
private Integer tenantId;
private String sysOrgCode;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -0,0 +1,54 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 烘胶分类管理主表(表 mes_xsl_drying_category
*/
@Data
@TableName("mes_xsl_drying_category")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES烘胶分类管理")
public class MesXslDryingCategory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "分类名称", width = 24)
@Schema(description = "分类名称(同租户未删除数据中唯一)")
private String categoryName;
private Integer tenantId;
private String sysOrgCode;
@Excel(name = "创建人", width = 15)
private String createBy;
@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
@TableField(exist = false)
@Schema(description = "物料明细")
private List<MesXslDryingCategoryMaterial> materialList;
}

View File

@@ -0,0 +1,54 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 烘胶分类物料明细(表 mes_xsl_drying_category_material
*/
@Data
@TableName("mes_xsl_drying_category_material")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES烘胶分类物料明细")
public class MesXslDryingCategoryMaterial implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Schema(description = "主表主键 mes_xsl_drying_category.id")
private String dryingCategoryId;
@Schema(description = "密炼物料主键 mes_mixer_material.id")
private String mixerMaterialId;
@Schema(description = "物料编码冗余")
private String materialCode;
@Schema(description = "物料名称冗余")
private String materialName;
@Schema(description = "物料描述冗余")
private String materialDesc;
private Integer sortNo;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -0,0 +1,53 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 烘胶房管理(表 mes_xsl_drying_room
*/
@Data
@TableName("mes_xsl_drying_room")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES烘胶房管理")
public class MesXslDryingRoom implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Schema(description = "烘胶房编码(同租户未删除数据中唯一)")
private String roomCode;
@Schema(description = "烘胶房名称(同租户未删除数据中唯一)")
private String roomName;
@Schema(description = "烘胶开始日期(月日,格式 MM-DD不含年份")
private String dryingStartMd;
@Schema(description = "烘胶结束日期(月日,格式 MM-DD不含年份")
private String dryingEndMd;
private Integer tenantId;
private String sysOrgCode;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -0,0 +1,67 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 烘胶房库位(表 mes_xsl_drying_room_slot
*/
@Data
@TableName("mes_xsl_drying_room_slot")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES烘胶房库位")
public class MesXslDryingRoomSlot implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "烘胶房库位", width = 20)
@Schema(description = "烘胶房库位(同烘胶房内未删除数据中唯一)")
private String slotName;
@Schema(description = "所属烘胶房主键 mes_xsl_drying_room.id")
private String dryingRoomId;
@Excel(name = "所属烘胶房", width = 20)
@Schema(description = "所属烘胶房名称冗余")
private String dryingRoomName;
@Schema(description = "存放物料分类主键 mes_xsl_drying_category.id")
private String dryingCategoryId;
@Excel(name = "存放物料", width = 20)
@Schema(description = "烘胶分类名称冗余")
private String categoryName;
@Excel(name = "库位容量", width = 15)
@Schema(description = "库位容量")
private BigDecimal slotCapacity;
private Integer tenantId;
private String sysOrgCode;
@Excel(name = "创建人", width = 15)
private String createBy;
@Excel(name = "创建时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -0,0 +1,69 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 人工小料计划维护
*/
@Data
@TableName("mes_xsl_manual_small_material_plan_maintain")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "人工小料计划维护")
public class MesXslManualSmallMaterialPlanMaintain implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "排序号", width = 10)
private Integer sortNo;
@Excel(name = "配方名称", width = 20)
private String formulaName;
@Excel(name = "早班序号", width = 12)
private Integer morningSeqNo;
@Excel(name = "早班计划", width = 12)
private Integer morningPlanCount;
@Excel(name = "早班备注", width = 20)
private String morningRemark;
@Excel(name = "中班序号", width = 12)
private Integer noonSeqNo;
@Excel(name = "中班计划", width = 12)
private Integer noonPlanCount;
@Excel(name = "中班备注", width = 20)
private String noonRemark;
@Excel(name = "夜班序号", width = 12)
private Integer nightSeqNo;
@Excel(name = "夜班计划", width = 12)
private Integer nightPlanCount;
@Excel(name = "夜班备注", width = 20)
private String nightRemark;
private Integer tenantId;
private String sysOrgCode;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -38,6 +38,16 @@ public class MesXslMixerAction implements Serializable {
@Schema(description = "设备名称冗余")
private String equipmentName;
//update-begin---author:GHT ---date:20260617 for【MES上辅机】密炼动作秒级采集-补全机台字段-----------
@Excel(name = "机台编号", width = 15)
@Schema(description = "机台编号(采集自中间表 EquipID")
private String equipId;
@Excel(name = "机台类型", width = 15)
@Schema(description = "机台类型(采集自中间表 EquipType")
private String equipType;
//update-end---author:GHT ---date:20260617 for【MES上辅机】密炼动作秒级采集-补全机台字段-----------
@Excel(name = "动作名称", width = 20)
@Schema(description = "动作名称")
private String actionName;

View File

@@ -0,0 +1,99 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 密炼生产计划维护
*/
@Data
@TableName("mes_xsl_mixing_production_plan")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "密炼生产计划维护")
public class MesXslMixingProductionPlan implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "排序号", width = 10)
@Schema(description = "排序号")
private Integer sortNo;
@Excel(name = "机台", width = 20, dictTable = "mes_xsl_equipment_ledger", dicText = "equipment_name", dicCode = "id")
@Dict(dictTable = "mes_xsl_equipment_ledger", dicText = "equipment_name", dicCode = "id")
@Schema(description = "机台ID")
private String machineId;
@Excel(name = "机台", width = 20)
@Schema(description = "机台名称")
private String machineName;
@Excel(name = "班次标识", width = 10)
@Schema(description = "班次标识1早班 2中班 3晚班")
private Integer shiftFlag;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Schema(description = "计划日期(保存时写入当前日期)")
private Date planDate;
@Schema(description = "计划号yyyyMMddA三位流水")
private String planNo;
@Schema(description = "计划ID母胶/终胶计划)")
private String planId;
@Schema(description = "计划类型 M母胶/F终胶")
private String planType;
@Schema(description = "生产订单ID")
private String sourceOrderId;
@Schema(description = "胶料ID取母胶/终胶计划materialCode")
private String materialId;
@Schema(description = "胶料名称(取母胶/终胶计划mesMaterialName")
private String materialName;
@Excel(name = "生产订单", width = 20)
private String orderNo;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Schema(description = "订单日期")
private Date orderDate;
@Excel(name = "配方名称", width = 20)
private String formulaName;
@Excel(name = "计划重量", width = 15)
private BigDecimal planWeight;
@Excel(name = "计划车数", width = 12)
private Integer plannedCarCount;
@Excel(name = "已排产车数", width = 12)
private Integer scheduledCarCount;
@Excel(name = "完成车数", width = 12)
private Integer finishedCarCount;
@Excel(name = "计划", width = 12)
private Integer planCount;
@Excel(name = "备注", width = 20)
private String remark;
private Integer tenantId;
private String sysOrgCode;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -89,6 +89,20 @@ public class MesXslMixingSpec implements Serializable {
@Schema(description = "自动小料打印设定")
private String autoSmallPrintSetting;
//update-begin---author:cursor ---date:20260612 for【XSLMES-20260612-A02】混炼示方小料称重上下限容差-----------
@Schema(description = "人工小料计量下限容差(KG)")
private BigDecimal manualSmallWeighLowerTol;
@Schema(description = "人工小料计量上限容差(KG)")
private BigDecimal manualSmallWeighUpperTol;
@Schema(description = "自动小料计量下限容差(KG)")
private BigDecimal autoSmallWeighLowerTol;
@Schema(description = "自动小料计量上限容差(KG)")
private BigDecimal autoSmallWeighUpperTol;
//update-end---author:cursor ---date:20260612 for【XSLMES-20260612-A02】混炼示方小料称重上下限容差-----------
@Schema(description = "设定车数")
private Integer setTrainCount;

View File

@@ -0,0 +1,71 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 混炼示方历史记录
*/
@Data
@TableName("mes_xsl_mixing_spec_history")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "混炼示方历史记录")
public class MesXslMixingSpecHistory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
@Schema(description = "混炼示方主表ID")
private String mixingSpecId;
@Excel(name = "规格名", width = 20)
@Schema(description = "规格名")
private String specName;
@Excel(name = "发行编号", width = 16)
@Schema(description = "发行编号")
private String issueNumber;
@Excel(name = "版本号", width = 10)
@Schema(description = "版本号")
private String versionNo;
@Excel(name = "操作类型", width = 10, dicCode = "xslmes_formula_spec_edit_log_action")
@Dict(dicCode = "xslmes_formula_spec_edit_log_action")
@Schema(description = "操作类型 create=新增 update=修改")
private String actionType;
@Schema(description = "完整快照JSON")
private String snapshotJson;
@Excel(name = "操作时间", width = 20, format = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Schema(description = "操作时间")
private Date operateTime;
@Schema(description = "操作人账号")
private String operateBy;
@Excel(name = "操作人", width = 14)
@Schema(description = "操作人姓名")
private String operateByName;
@Schema(description = "租户ID")
private Integer tenantId;
}

View File

@@ -0,0 +1,54 @@
package org.jeecg.modules.xslmes.entity;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* 原材料需求计划汇总(按原材料或按机台+原材料)
*/
@Data
@Schema(description = "原材料需求计划汇总")
public class MesXslRawMaterialDemandPlanSummary implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键")
private String id;
@Excel(name = "机台", width = 20)
@Schema(description = "机台")
private String machineName;
@Excel(name = "计划日期", width = 14, format = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
@Schema(description = "计划日期")
private Date planDate;
@Schema(description = "物料ID(密炼物料信息ID)")
private String materialId;
@Excel(name = "ERP编号", width = 18)
@Schema(description = "ERP编号")
private String erpCode;
@Excel(name = "原材料名称", width = 24)
@Schema(description = "原材料名称")
private String rawMaterialName;
@Excel(name = "需求重量", width = 15)
@Schema(description = "需求重量")
private BigDecimal demandWeight;
@Excel(name = "标准重量", width = 15)
@Schema(description = "标准重量")
private BigDecimal standardWeight;
@Excel(name = "实际重量", width = 15)
@Schema(description = "实际重量")
private BigDecimal actualWeight;
}

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
@@ -32,8 +33,8 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Excel(name = "", width = 16)
@Schema(description = "单号JL+yyyyMMdd+4位流水")
@Excel(name = "快检记录", width = 16)
@Schema(description = "快检记录号(yyyyMMdd+4位流水+胶料名称")
private String recordNo;
@Schema(description = "胶料ID mes_material.id")
@@ -46,14 +47,25 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@Schema(description = "引用的实验标准ID")
private String stdId;
@Schema(description = "生产机台ID")
@Excel(name = "实验标准", width = 20)
@Schema(description = "实验标准名称冗余")
private String stdName;
@Schema(description = "实验方法ID")
private String testMethodId;
@Excel(name = "实验方法", width = 20)
@Schema(description = "实验方法名称冗余")
private String testMethodName;
@Schema(description = "炼机台ID")
private String prodEquipmentLedgerId;
@Excel(name = "生产机台", width = 16)
@Schema(description = "生产机台名称冗余")
@Excel(name = "机台", width = 16)
@Schema(description = "机台名称冗余")
private String prodEquipmentName;
@Excel(name = "生产日期", width = 12, format = "yyyy-MM-dd")
@Excel(name = "密炼日期", width = 12, format = "yyyy-MM-dd")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date productionDate;
@@ -69,7 +81,7 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@Dict(dicCode = "xslmes_rubber_quick_test_work_team")
private String workTeam;
@Excel(name = "验次数", width = 10)
@Excel(name = "验次数", width = 10)
private Integer inspectTimes;
@Excel(name = "检验时间", width = 18, format = "yyyy-MM-dd HH:mm:ss")
@@ -78,6 +90,7 @@ public class MesXslRubberQuickTestRecord implements Serializable {
private Date inspectTime;
@Schema(description = "检验人用户ID")
@Dict(dictTable = "sys_user", dicText = "realname", dicCode = "id")
private String inspectorUserId;
private String inspectorUsername;
@@ -85,17 +98,17 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@Excel(name = "检验人", width = 12)
private String inspectorRealname;
@Schema(description = "验类型ID")
@Schema(description = "验类型ID")
private String quickTestTypeId;
@Excel(name = "验类型", width = 16)
@Excel(name = "验类型", width = 16)
private String quickTestTypeName;
@Excel(name = "检验结果", width = 10, dicCode = "xslmes_rubber_quick_test_record_result")
@Dict(dicCode = "xslmes_rubber_quick_test_record_result")
private String inspectResult;
@Excel(name = "生产计划", width = 16)
@Excel(name = "密炼计划", width = 16)
private String productionPlanNo;
@Schema(description = "检验机台ID")
@@ -129,4 +142,21 @@ public class MesXslRubberQuickTestRecord implements Serializable {
@TableField(exist = false)
private List<MesXslRubberQuickTestRecordLine> lineList;
@TableField(exist = false)
@Schema(description = "原始数据明细(试验结果全部检测值)")
private List<MesXslRubberQuickTestRecordRawLine> rawLineList;
//update-begin---author:jiangxh ---date:2026-06-22 for【快检记录】数据标准明细与曲线图-----------
@TableField(exist = false)
@Schema(description = "数据标准明细(实验标准快照)")
private List<MesXslRubberQuickTestRecordStdLine> stdLineList;
@TableField(exist = false)
@Schema(description = "曲线图数据点")
//update-begin---author:jiangxh ---date:2026-06-29 for【快检记录】主表曲线图列表JSON别名-----------
@JsonAlias("chart_point_list")
//update-end---author:jiangxh ---date:2026-06-29 for【快检记录】主表曲线图列表JSON别名-----------
private List<MesXslRubberQuickTestRecordChartPoint> chartPointList;
//update-end---author:jiangxh ---date:2026-06-22 for【快检记录】数据标准明细与曲线图-----------
}

View File

@@ -0,0 +1,67 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 胶料快检记录曲线图数据点
*/
@Data
@TableName("mes_xsl_rubber_quick_test_record_chart_point")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES胶料快检记录曲线图数据点")
public class MesXslRubberQuickTestRecordChartPoint implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id")
private String recordId;
//update-begin---author:jiangxh ---date:2026-06-29 for【快检记录】曲线图字段兼容桌面端与下划线JSON-----------
@Excel(name = "时间(min)", width = 12, type = 10)
@JsonAlias("time_min")
private BigDecimal timeMin;
@Excel(name = "上模温度", width = 12, type = 10)
@JsonAlias("upper_temp")
private BigDecimal upperTemp;
@Excel(name = "下模温度", width = 12, type = 10)
@JsonAlias("lower_temp")
private BigDecimal lowerTemp;
@Excel(name = "S'(dNm)", width = 12, type = 10)
@JsonAlias("torque_s")
private BigDecimal torqueS;
@JsonAlias("sort_no")
private Integer sortNo;
//update-end---author:jiangxh ---date:2026-06-29 for【快检记录】曲线图字段兼容桌面端与下划线JSON-----------
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -0,0 +1,72 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecg.common.aspect.annotation.Dict;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 胶料快检记录原始数据明细(试验结果全部检测值)
*/
@Data
@TableName("mes_xsl_rubber_quick_test_record_raw_line")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES胶料快检记录原始数据明细")
public class MesXslRubberQuickTestRecordRawLine implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id")
private String recordId;
@Excel(name = "编号", width = 14)
@Schema(description = "试验结果编号如1_1")
private String rowNo;
@Schema(description = "数据点ID")
private String dataPointId;
@Excel(name = "数据点", width = 18)
private String inspectItem;
@Excel(name = "下限值", width = 12, type = 10)
private BigDecimal lowerLimit;
@Excel(name = "上限值", width = 12, type = 10)
private BigDecimal upperLimit;
@Excel(name = "检测值", width = 12, type = 10)
private BigDecimal inspectValue;
@Excel(name = "行检验结果", width = 10, dicCode = "xslmes_rubber_quick_test_record_result")
@Dict(dicCode = "xslmes_rubber_quick_test_record_result")
@Schema(description = "行检验结果1合格0不合格")
private String rowInspectResult;
private Integer sortNo;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -0,0 +1,68 @@
package org.jeecg.modules.xslmes.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.jeecgframework.poi.excel.annotation.Excel;
import org.springframework.format.annotation.DateTimeFormat;
/**
* MES 胶料快检记录数据标准明细(实验标准快照)
*/
@Data
@TableName("mes_xsl_rubber_quick_test_record_std_line")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES胶料快检记录数据标准明细")
public class MesXslRubberQuickTestRecordStdLine implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
private String id;
@Schema(description = "主表ID mes_xsl_rubber_quick_test_record.id")
private String recordId;
@Schema(description = "数据点ID")
private String dataPointId;
@Excel(name = "数据点", width = 18)
private String pointName;
@Excel(name = "下限值", width = 12, type = 10)
private BigDecimal lowerLimit;
@Excel(name = "上限值", width = 12, type = 10)
private BigDecimal upperLimit;
@Excel(name = "下限预警", width = 12, type = 10)
private BigDecimal lowerWarn;
@Excel(name = "上限预警", width = 12, type = 10)
private BigDecimal upperWarn;
@Excel(name = "目标值", width = 12, type = 10)
private BigDecimal targetValue;
private Integer sortNo;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -106,4 +106,12 @@ public class MesXslRubberQuickTestStd implements Serializable {
@TableField(exist = false)
@Schema(description = "标准明细")
private List<MesXslRubberQuickTestStdLine> lineList;
@TableField(exist = false)
@Schema(description = "实验类型ID来自实验方法桌面端展示")
private String quickTestTypeId;
@TableField(exist = false)
@Schema(description = "实验类型名称(来自实验方法,桌面端展示)")
private String quickTestTypeName;
}

View File

@@ -0,0 +1,35 @@
package org.jeecg.modules.xslmes.entity;
import io.swagger.v3.oas.annotations.media.Schema;
import java.io.Serializable;
import java.math.BigDecimal;
import lombok.Data;
import org.jeecgframework.poi.excel.annotation.Excel;
/**
* 小料需求计划汇总(自动/人工)
*/
@Data
@Schema(description = "小料需求计划汇总")
public class MesXslSmallMaterialDemandPlanSummary implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "主键")
private String id;
@Excel(name = "机台", width = 20)
@Schema(description = "机台")
private String machineName;
@Excel(name = "原材料名称", width = 24)
@Schema(description = "原材料名称")
private String rawMaterialName;
@Excel(name = "需求重量(KG)", width = 18)
@Schema(description = "需求重量(KG)")
private BigDecimal demandWeight;
@Schema(description = "统计日期(yyyy-MM-dd)")
private String statDate;
}

View File

@@ -0,0 +1,7 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslAutoSmallMaterialPlanMaintain;
public interface MesXslAutoSmallMaterialPlanMaintainMapper
extends BaseMapper<MesXslAutoSmallMaterialPlanMaintain> {}

View File

@@ -0,0 +1,9 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslDryingCategory;
/**
* MES 烘胶分类管理
*/
public interface MesXslDryingCategoryMapper extends BaseMapper<MesXslDryingCategory> {}

View File

@@ -0,0 +1,9 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslDryingCategoryMaterial;
/**
* MES 烘胶分类物料明细
*/
public interface MesXslDryingCategoryMaterialMapper extends BaseMapper<MesXslDryingCategoryMaterial> {}

View File

@@ -0,0 +1,9 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslDryingRoom;
/**
* MES 烘胶房管理
*/
public interface MesXslDryingRoomMapper extends BaseMapper<MesXslDryingRoom> {}

View File

@@ -0,0 +1,9 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslDryingRoomSlot;
/**
* MES 烘胶房库位
*/
public interface MesXslDryingRoomSlotMapper extends BaseMapper<MesXslDryingRoomSlot> {}

View File

@@ -0,0 +1,7 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslManualSmallMaterialPlanMaintain;
public interface MesXslManualSmallMaterialPlanMaintainMapper
extends BaseMapper<MesXslManualSmallMaterialPlanMaintain> {}

View File

@@ -0,0 +1,6 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslMixingProductionPlan;
public interface MesXslMixingProductionPlanMapper extends BaseMapper<MesXslMixingProductionPlan> {}

View File

@@ -0,0 +1,9 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslMixingSpecHistory;
/**
* 混炼示方历史记录
*/
public interface MesXslMixingSpecHistoryMapper extends BaseMapper<MesXslMixingSpecHistory> {}

View File

@@ -0,0 +1,6 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordChartPoint;
public interface MesXslRubberQuickTestRecordChartPointMapper extends BaseMapper<MesXslRubberQuickTestRecordChartPoint> {}

View File

@@ -0,0 +1,6 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
public interface MesXslRubberQuickTestRecordRawLineMapper extends BaseMapper<MesXslRubberQuickTestRecordRawLine> {}

View File

@@ -0,0 +1,7 @@
package org.jeecg.modules.xslmes.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordStdLine;
public interface MesXslRubberQuickTestRecordStdLineMapper extends BaseMapper<MesXslRubberQuickTestRecordStdLine> {
}

View File

@@ -0,0 +1,44 @@
package org.jeecg.modules.xslmes.mcs.config;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
import org.jeecg.modules.xslmes.mcs.service.IMesXslMcsDbConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 启动时加载中间库配置,覆盖 application.yml 中的 sqlserver_mcs 连接
*/
@Slf4j
@Component
@Order(100)
public class McsDataSourceInitializer implements ApplicationRunner {
@Autowired
private IMesXslMcsDbConfigService mcsDbConfigService;
@Autowired
private McsDataSourceManager mcsDataSourceManager;
//update-begin---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库可视化配置-----------
@Override
public void run(ApplicationArguments args) {
try {
MesXslMcsDbConfig config = mcsDbConfigService.loadStartupConfig();
if (config != null) {
mcsDataSourceManager.applyConfig(config);
log.info("[MCS中间库] 已加载数据库中的中间库配置 tenantId={}, status={}, host={}:{}",
config.getTenantId(), config.getStatus(), config.getServerHost(), config.getServerPort());
} else {
log.info("[MCS中间库] 数据库中无中间库配置,继续使用 application.yml 中的 sqlserver_mcs");
}
} catch (Exception e) {
log.error("[MCS中间库] 启动加载配置失败,将使用 yml 默认连接", e);
}
}
//update-end---author:GHT ---date:20260616 for【MES上辅机】启动时加载中间库可视化配置-----------
}

View File

@@ -0,0 +1,64 @@
package org.jeecg.modules.xslmes.mcs.config;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 注册 MCS 中间库 HTTP 拦截器(读取/写入开关在接口层生效)
*/
@Configuration
public class McsWebMvcConfig implements WebMvcConfigurer {
@Autowired
private McsDataSourceManager mcsDataSourceManager;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(mcsReadWriteInterceptor())
.addPathPatterns("/xslmes/mcs/**")
.excludePathPatterns("/xslmes/mcs/dbConfig/**");
}
//update-begin---author:GHT ---date:20260616 for【MES上辅机】HTTP层拦截中间库读写请求-----------
private HandlerInterceptor mcsReadWriteInterceptor() {
return new HandlerInterceptor() {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (!mcsDataSourceManager.hasSavedConfig()) {
return true;
}
String uri = request.getRequestURI();
if (uri.contains("/mcs/dbConfig")) {
return true;
}
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
return true;
}
if (!mcsDataSourceManager.isReadEnabled()) {
throw new JeecgBootException("中间库读取已关闭,请在「中间库连接配置」中开启读取开关并保存");
}
if (isWriteRequest(request, uri) && !mcsDataSourceManager.isWriteEnabled()) {
throw new JeecgBootException("中间库写入已关闭,请在「中间库连接配置」中开启写入开关并保存");
}
return true;
}
private boolean isWriteRequest(HttpServletRequest request, String uri) {
String method = request.getMethod();
boolean mutating = "POST".equalsIgnoreCase(method)
|| "PUT".equalsIgnoreCase(method)
|| "DELETE".equalsIgnoreCase(method)
|| "PATCH".equalsIgnoreCase(method);
return mutating && uri.toLowerCase().contains("mestomcs");
}
};
}
//update-end---author:GHT ---date:20260616 for【MES上辅机】HTTP层拦截中间库读写请求-----------
}

View File

@@ -0,0 +1,85 @@
package org.jeecg.modules.xslmes.mcs.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.config.TenantContext;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig;
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
import org.jeecg.modules.xslmes.mcs.service.IMesXslMcsDbConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* MES上辅机 SQL Server 中间库连接配置
*/
@Tag(name = "MES上辅机中间库配置")
@RestController
@RequestMapping("/xslmes/mcs/dbConfig")
public class MesXslMcsDbConfigController {
@Autowired
private IMesXslMcsDbConfigService mcsDbConfigService;
@Autowired
private McsDataSourceManager mcsDataSourceManager;
private Integer resolveTenantId(Integer tenantId) {
if (MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL) {
if (tenantId == null) {
tenantId = oConvertUtils.getInt(TenantContext.getTenant(), -1);
}
} else if (tenantId == null) {
tenantId = oConvertUtils.getInt(TenantContext.getTenant(), 0);
}
return tenantId;
}
@Operation(summary = "获取中间库配置")
@GetMapping("/get")
public Result<MesXslMcsDbConfig> getConfig(@RequestParam(name = "tenantId", required = false) Integer tenantId) {
return Result.OK(mcsDbConfigService.getCurrentConfig(resolveTenantId(tenantId)));
}
@Operation(summary = "保存中间库配置")
@PostMapping("/save")
public Result<String> saveConfig(@RequestBody MesXslMcsDbConfig config) {
if (config.getTenantId() == null) {
config.setTenantId(resolveTenantId(null));
}
return mcsDbConfigService.saveOrUpdateConfig(config);
}
@Operation(summary = "测试中间库连接")
@GetMapping("/testConnect")
public Result<String> testConnect(@RequestParam(name = "tenantId", required = false) Integer tenantId) {
return mcsDbConfigService.testConnection(resolveTenantId(tenantId));
}
@Operation(summary = "删除中间库配置")
@DeleteMapping("/delete")
public Result<String> deleteConfig(@RequestParam(name = "id") String id) {
return mcsDbConfigService.deleteConfig(id);
}
@Operation(summary = "获取中间库连接状态")
@GetMapping("/status")
public Result<Map<String, Object>> status() {
Map<String, Object> data = new LinkedHashMap<>();
MesXslMcsDbConfig cfg = mcsDataSourceManager.getCachedConfig();
data.put("dbConfigActive", mcsDataSourceManager.isDbConfigActive());
data.put("readEnabled", mcsDataSourceManager.isReadEnabled());
data.put("writeEnabled", mcsDataSourceManager.isWriteEnabled());
if (cfg != null) {
data.put("serverHost", cfg.getServerHost());
data.put("serverPort", cfg.getServerPort());
data.put("dbName", cfg.getDbName());
}
return Result.OK(data);
}
}

View File

@@ -0,0 +1,150 @@
package org.jeecg.modules.xslmes.mcs.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
import org.jeecg.modules.xslmes.mcs.mapper.McsMetaMapper;
import org.jeecg.modules.xslmes.mcs.service.IMesXslMcsSyncConfigService;
import org.jeecg.modules.xslmes.mcs.sync.McsSyncScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* MES上辅机 中间表采集配置(表/字段绑定 + 采集操作 + 元数据)
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】采集配置-表与字段绑定
*/
@Tag(name = "MES上辅机采集配置")
@RestController
@RequestMapping("/xslmes/mcs/syncConfig")
public class MesXslMcsSyncConfigController {
@Autowired
private IMesXslMcsSyncConfigService syncConfigService;
@Autowired
private McsSyncScheduler syncScheduler;
@Autowired
private McsMetaMapper metaMapper;
@Autowired
private McsDataSourceManager mcsDataSourceManager;
@Operation(summary = "采集配置-分页列表")
@GetMapping("/list")
public Result<IPage<MesXslMcsSyncConfig>> list(MesXslMcsSyncConfig query,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
LambdaQueryWrapper<MesXslMcsSyncConfig> qw = new LambdaQueryWrapper<MesXslMcsSyncConfig>()
.eq(MesXslMcsSyncConfig::getDelFlag, 0)
.like(StringUtils.isNotBlank(query.getConfigName()), MesXslMcsSyncConfig::getConfigName, query.getConfigName())
.like(StringUtils.isNotBlank(query.getSourceTable()), MesXslMcsSyncConfig::getSourceTable, query.getSourceTable())
.orderByDesc(MesXslMcsSyncConfig::getUpdateTime);
IPage<MesXslMcsSyncConfig> page = syncConfigService.page(new Page<>(pageNo, pageSize), qw);
page.getRecords().forEach(c -> c.setRunning(syncScheduler.isRunning(c.getId())));
return Result.OK(page);
}
@Operation(summary = "采集配置-详情(含字段映射)")
@GetMapping("/queryById")
public Result<MesXslMcsSyncConfig> queryById(@RequestParam("id") String id) {
MesXslMcsSyncConfig cfg = syncConfigService.getDetail(id);
if (cfg == null) {
return Result.error("配置不存在");
}
cfg.setRunning(syncScheduler.isRunning(id));
return Result.OK(cfg);
}
@Operation(summary = "采集配置-按业务类型获取(密炼动作页用)")
@GetMapping("/getByBizType")
public Result<MesXslMcsSyncConfig> getByBizType(@RequestParam(name = "bizType", defaultValue = "MIX_ACT") String bizType) {
MesXslMcsSyncConfig cfg = syncConfigService.getByBizType(bizType);
if (cfg != null) {
cfg.setRunning(syncScheduler.isRunning(cfg.getId()));
}
return Result.OK(cfg);
}
@Operation(summary = "采集配置-新增")
@RequiresPermissions("xslmes:mcsSyncConfig:add")
@PostMapping("/add")
public Result<String> add(@RequestBody MesXslMcsSyncConfig config) {
config.setId(null);
return syncConfigService.saveConfig(config);
}
@Operation(summary = "采集配置-编辑")
@RequiresPermissions("xslmes:mcsSyncConfig:edit")
@PostMapping("/edit")
public Result<String> edit(@RequestBody MesXslMcsSyncConfig config) {
if (StringUtils.isBlank(config.getId())) {
return Result.error("缺少配置ID");
}
return syncConfigService.saveConfig(config);
}
@Operation(summary = "采集配置-删除")
@RequiresPermissions("xslmes:mcsSyncConfig:delete")
@DeleteMapping("/delete")
public Result<String> delete(@RequestParam("id") String id) {
return syncConfigService.deleteConfig(id);
}
@Operation(summary = "采集操作-是否采集+采集间隔")
@RequiresPermissions("xslmes:mcsSyncConfig:setting")
@PostMapping("/saveCollect")
public Result<String> saveCollect(@RequestBody MesXslMcsSyncConfig body) {
return syncConfigService.saveCollect(body);
}
// ===================== 元数据 =====================
@Operation(summary = "元数据-中间库表清单")
@GetMapping("/meta/sourceTables")
public Result<List<Map<String, Object>>> sourceTables() {
if (!mcsDataSourceManager.isDbConfigActive()) {
return Result.error("中间库未连接,请先在「中间库连接配置」中启用");
}
return Result.OK(metaMapper.listSourceTables());
}
@Operation(summary = "元数据-中间库表字段")
@GetMapping("/meta/sourceColumns")
public Result<List<Map<String, Object>>> sourceColumns(@RequestParam("table") String table) {
if (!mcsDataSourceManager.isDbConfigActive()) {
return Result.error("中间库未连接,请先在「中间库连接配置」中启用");
}
if (!table.matches("^[A-Za-z0-9_]+$")) {
return Result.error("非法表名");
}
return Result.OK(metaMapper.listSourceColumns(table));
}
@Operation(summary = "元数据-MES业务表清单(mes_xsl_前缀)")
@GetMapping("/meta/targetTables")
public Result<List<Map<String, Object>>> targetTables() {
return Result.OK(metaMapper.listTargetTables());
}
@Operation(summary = "元数据-MES表字段")
@GetMapping("/meta/targetColumns")
public Result<List<Map<String, Object>>> targetColumns(@RequestParam("table") String table) {
if (!table.matches("^[A-Za-z0-9_]+$")) {
return Result.error("非法表名");
}
return Result.OK(metaMapper.listTargetColumns(table));
}
}

View File

@@ -0,0 +1,48 @@
package org.jeecg.modules.xslmes.mcs.datasource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.jeecg.common.exception.JeecgBootException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* MCS 中间库读写开关守卫
* <ul>
* <li>读取开关拦截所有中间表查询McsToMes + MesToMcs 列表/详情等)</li>
* <li>写入开关:仅拦截 MES→MCS 方向的增删改</li>
* </ul>
*/
@Slf4j
@Aspect
@Component
@Order(1)
public class McsDataSourceGuardAspect {
@Autowired
private McsDataSourceManager mcsDataSourceManager;
//update-begin---author:GHT ---date:20260616 for【MES上辅机】读取开关拦截全部中间表查询-----------
@Before("(execution(* com.baomidou.mybatisplus.extension.service.IService+.*(..)) "
+ "&& (target(org.jeecg.modules.xslmes.mcs.service.impl.McsToMes*) "
+ "|| target(org.jeecg.modules.xslmes.mcs.service.impl.MesToMcs*)))")
public void guardRead(JoinPoint joinPoint) {
if (!mcsDataSourceManager.isReadEnabled()) {
throw new JeecgBootException("中间库读取已关闭,请在「中间库连接配置」中开启读取开关并保存");
}
}
@Before("execution(* org.jeecg.modules.xslmes.mcs.service.impl.MesToMcs*.save*(..)) || "
+ "execution(* org.jeecg.modules.xslmes.mcs.service.impl.MesToMcs*.update*(..)) || "
+ "execution(* org.jeecg.modules.xslmes.mcs.service.impl.MesToMcs*.remove*(..)) || "
+ "execution(* org.jeecg.modules.xslmes.mcs.service.impl.MesToMcs*.delete*(..))")
public void guardWrite(JoinPoint joinPoint) {
if (!mcsDataSourceManager.isWriteEnabled()) {
throw new JeecgBootException("中间库写入已关闭,请在「中间库连接配置」中开启写入开关并保存");
}
}
//update-end---author:GHT ---date:20260616 for【MES上辅机】读取开关拦截全部中间表查询-----------
}

View File

@@ -0,0 +1,250 @@
package org.jeecg.modules.xslmes.mcs.datasource;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import com.baomidou.dynamic.datasource.creator.DataSourceProperty;
import com.baomidou.dynamic.datasource.creator.druid.DruidConfig;
import com.baomidou.dynamic.datasource.creator.druid.DruidDataSourceCreator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.jeecg.common.util.dynamic.db.DataSourceCachePool;
import org.jeecg.modules.system.util.SecurityUtil;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.concurrent.atomic.AtomicReference;
/**
* MCS SQL Server 动态数据源管理器
* <p>配置保存后热刷新 sqlserver_mcs 数据源,无需改 application.yml</p>
*/
@Slf4j
@Component
public class McsDataSourceManager {
public static final String DS_KEY = "sqlserver_mcs";
private final AtomicReference<MesXslMcsDbConfig> cachedConfig = new AtomicReference<>();
@Autowired
private DataSource dataSource;
@Autowired
private DruidDataSourceCreator dataSourceCreator;
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.url:}")
private String ymlUrl;
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.username:}")
private String ymlUsername;
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.password:}")
private String ymlPassword;
@Value("${spring.datasource.dynamic.datasource.sqlserver_mcs.driver-class-name:com.microsoft.sqlserver.jdbc.SQLServerDriver}")
private String ymlDriverClassName;
public MesXslMcsDbConfig getCachedConfig() {
return cachedConfig.get();
}
public boolean hasSavedConfig() {
return cachedConfig.get() != null;
}
public boolean isDbConfigActive() {
MesXslMcsDbConfig cfg = cachedConfig.get();
if (cfg == null || !Integer.valueOf(1).equals(cfg.getStatus())) {
return false;
}
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
return routing.getDataSources().containsKey(DS_KEY);
}
public boolean isReadEnabled() {
MesXslMcsDbConfig cfg = cachedConfig.get();
if (cfg == null) {
return true;
}
return Integer.valueOf(1).equals(cfg.getReadEnabled());
}
public boolean isWriteEnabled() {
MesXslMcsDbConfig cfg = cachedConfig.get();
if (cfg == null) {
return true;
}
return Integer.valueOf(1).equals(cfg.getWriteEnabled());
}
//update-begin---author:GHT ---date:20260616 for【MES上辅机】SQL Server中间库可视化配置-----------
/**
* 将配置应用到动态数据源(启用时注册/更新,禁用时移除)
*/
public void applyConfig(MesXslMcsDbConfig config) {
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
closeAndRemoveDataSource(routing);
DataSourceCachePool.removeCache(DS_KEY);
if (config == null) {
cachedConfig.set(null);
restoreYmlDataSource(routing);
log.info("[MCS中间库] 已清除页面配置");
return;
}
if (Integer.valueOf(1).equals(config.getStatus())) {
try {
String plainPassword = decryptPassword(config.getDbPassword());
DataSourceProperty property = buildDataSourceProperty(config, plainPassword);
DataSource mcsDs = dataSourceCreator.createDataSource(property);
routing.addDataSource(DS_KEY, mcsDs);
cachedConfig.set(config);
log.info("[MCS中间库] 动态数据源 {} 已热刷新(无需重启): {}:{}/{}", DS_KEY,
config.getServerHost(), config.getServerPort(), config.getDbName());
} catch (Exception e) {
cachedConfig.set(config);
log.error("[MCS中间库] 刷新动态数据源失败", e);
throw new RuntimeException("刷新中间库数据源失败:" + e.getMessage(), e);
}
return;
}
cachedConfig.set(config);
restoreYmlDataSource(routing);
log.info("[MCS中间库] 连接未启用,读写开关仍按页面配置生效");
}
private void closeAndRemoveDataSource(DynamicRoutingDataSource routing) {
if (!routing.getDataSources().containsKey(DS_KEY)) {
return;
}
DataSource old = routing.getDataSource(DS_KEY);
routing.removeDataSource(DS_KEY);
closeDataSourceQuietly(old);
}
private void closeDataSourceQuietly(DataSource ds) {
if (ds instanceof DruidDataSource druid && druid.isEnable()) {
try {
druid.close();
} catch (Exception e) {
log.warn("[MCS中间库] 关闭旧连接池失败: {}", e.getMessage());
}
}
}
/**
* 测试 JDBC 连通性(不写入动态数据源)
*/
public String testConnection(MesXslMcsDbConfig config, String plainPassword) {
if (config == null) {
return "配置为空";
}
String jdbcUrl = buildJdbcUrl(config);
try {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
try (Connection conn = DriverManager.getConnection(jdbcUrl, config.getDbUsername(), plainPassword)) {
if (conn.isValid(5)) {
return null;
}
return "连接无效";
}
} catch (Exception e) {
log.warn("[MCS中间库] 连接测试失败: {}", e.getMessage());
return e.getMessage();
}
}
public String buildJdbcUrl(MesXslMcsDbConfig config) {
int loginTimeout = config.getLoginTimeout() != null ? config.getLoginTimeout() : 120;
int connectTimeout = config.getConnectTimeout() != null ? config.getConnectTimeout() : 120000;
String host = resolveHost(config);
int port = config.getServerPort() != null ? config.getServerPort() : 1433;
String dbName = StringUtils.isNotBlank(config.getDbName()) ? config.getDbName() : "MES_ShareDB";
return "jdbc:sqlserver://" + host + ":" + port
+ ";DatabaseName=" + dbName
+ ";encrypt=false;trustServerCertificate=true;SelectMethod=cursor"
+ ";loginTimeout=" + loginTimeout
+ ";connectTimeout=" + connectTimeout + ";";
}
private DataSourceProperty buildDataSourceProperty(MesXslMcsDbConfig config, String plainPassword) {
DataSourceProperty property = new DataSourceProperty();
property.setPoolName(DS_KEY);
property.setDriverClassName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
property.setUrl(buildJdbcUrl(config));
property.setUsername(config.getDbUsername());
property.setPassword(plainPassword);
applySqlServerDruidConfig(property);
return property;
}
/**
* SQL Server 不支持 Oracle/MySQL 的 DUAL 表,覆盖全局 validationQuery 避免连接池校验失败
*/
private void applySqlServerDruidConfig(DataSourceProperty property) {
DruidConfig druid = property.getDruid();
if (druid == null) {
druid = new DruidConfig();
property.setDruid(druid);
}
druid.setValidationQuery("SELECT 1");
}
private void restoreYmlDataSource(DynamicRoutingDataSource routing) {
if (StringUtils.isBlank(ymlUrl)) {
log.warn("[MCS中间库] yml 中未配置 sqlserver_mcs无法恢复默认数据源");
return;
}
try {
DataSourceProperty property = new DataSourceProperty();
property.setPoolName(DS_KEY);
property.setDriverClassName(ymlDriverClassName);
property.setUrl(ymlUrl);
property.setUsername(ymlUsername);
property.setPassword(ymlPassword);
applySqlServerDruidConfig(property);
routing.addDataSource(DS_KEY, dataSourceCreator.createDataSource(property));
} catch (Exception e) {
log.error("[MCS中间库] 恢复 yml 默认数据源失败", e);
}
}
private String resolveHost(MesXslMcsDbConfig config) {
String host = config.getServerHost() == null ? "" : config.getServerHost().trim();
if (host.contains(":")) {
String[] parts = host.split(":", 2);
host = parts[0];
if (config.getServerPort() == null || config.getServerPort() == 1433) {
try {
config.setServerPort(Integer.parseInt(parts[1]));
} catch (NumberFormatException ignored) {
// 端口解析失败时保留原端口
}
}
}
return host;
}
public String decryptPassword(String encrypted) {
if (StringUtils.isBlank(encrypted)) {
return "";
}
try {
return SecurityUtil.jiemi(encrypted);
} catch (Exception e) {
return encrypted;
}
}
public String encryptPassword(String plain) {
if (StringUtils.isBlank(plain)) {
return plain;
}
return SecurityUtil.jiami(plain);
}
//update-end---author:GHT ---date:20260616 for【MES上辅机】SQL Server中间库可视化配置-----------
}

View File

@@ -0,0 +1,80 @@
package org.jeecg.modules.xslmes.mcs.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* MES上辅机 SQL Server 中间库配置
*/
@Data
@TableName("mes_xsl_mcs_db_config")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES上辅机SQL Server中间库配置")
public class MesXslMcsDbConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
@Schema(description = "租户ID")
private Integer tenantId;
@Schema(description = "服务器地址")
private String serverHost;
@Schema(description = "端口")
private Integer serverPort;
@Schema(description = "数据库名")
private String dbName;
@Schema(description = "用户名")
private String dbUsername;
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
@Schema(description = "密码")
private String dbPassword;
@Schema(description = "读取开关(0-关,1-开)")
private Integer readEnabled;
@Schema(description = "写入开关(0-关,1-开)")
private Integer writeEnabled;
@Schema(description = "启用状态(0-关,1-开)")
private Integer status;
@Schema(description = "登录超时(秒)")
private Integer loginTimeout;
@Schema(description = "连接超时(毫秒)")
private Integer connectTimeout;
@Schema(description = "备注")
private String remark;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
}

View File

@@ -0,0 +1,126 @@
package org.jeecg.modules.xslmes.mcs.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* MES上辅机 中间表采集配置(通用)
* <p>按 bizType 区分不同业务(密炼动作/报警/配方等),供秒级定时采集统一复用</p>
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】密炼动作秒级采集
*/
@Data
@TableName("mes_xsl_mcs_sync_config")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES上辅机中间表采集配置")
public class MesXslMcsSyncConfig implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
@Schema(description = "业务类型(采集任务唯一标识,如 MIX_ACT 密炼动作;通用配置可为空)")
private String bizType;
@Schema(description = "配置名称")
private String configName;
@Schema(description = "业务名称")
private String bizName;
@Schema(description = "源中间表名")
private String sourceTable;
@Schema(description = "源中间表注释")
private String sourceTableComment;
@Schema(description = "MES目标表名")
private String targetTable;
@Schema(description = "MES目标表注释")
private String targetTableComment;
@Schema(description = "采集时间间隔(秒)默认1秒")
private Integer intervalSeconds;
@Schema(description = "采集状态(0停止,1运行)")
private String status;
@Schema(description = "采集模式(FULL全量匹配,TIME时间匹配,INCR增量匹配-标记位回写)")
private String syncMode;
@Schema(description = "时间列/标记列(源表列名)。TIME模式=时间列INCR模式=同步标记列(为空表示未采集,采集后回写'1')")
private String incrColumn;
@Schema(description = "时间范围(TODAY当天,LAST7最近七天)")
private String timeWindow;
@Schema(description = "每轮最大采集行数(INCR模式TOP N)")
private Integer batchLimit;
@Schema(description = "增量采集高水位(INCR模式自动维护)")
private String lastWatermark;
@Schema(description = "增量标记采集条件(IS_NULL为空,EQ_EMPTY等于匹配值,NE_EMPTY不等于匹配值)INCR模式用")
private String flagCondition;
//update-begin---author:GHT ---date:20260617 for【MES上辅机】增量采集条件等于/不等于支持自定义匹配值-----------
@Schema(description = "增量标记采集条件比较值(EQ_EMPTY/NE_EMPTY 用,留空表示空字符串)INCR模式用")
private String flagMatchValue;
//update-end---author:GHT ---date:20260617 for【MES上辅机】增量采集条件等于/不等于支持自定义匹配值-----------
@Schema(description = "增量标记采集完成后回写值(默认1)INCR模式用")
private String flagWriteValue;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@Schema(description = "最近一次采集时间")
private Date lastSyncTime;
@Schema(description = "最近一次采集结果")
private String lastSyncResult;
@Schema(description = "备注")
private String remark;
@Schema(description = "租户ID")
private Integer tenantId;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
@TableField(exist = false)
@Schema(description = "字段映射明细(主子保存/详情用)")
private List<MesXslMcsSyncField> fieldList;
@TableField(exist = false)
@Schema(description = "采集任务是否运行中(运行态由调度器实时给出)")
private Boolean running;
}

View File

@@ -0,0 +1,75 @@
package org.jeecg.modules.xslmes.mcs.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.util.Date;
/**
* MES上辅机 采集字段映射(中间库源字段 → MES目标字段
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】采集配置-表与字段绑定
*/
@Data
@TableName("mes_xsl_mcs_sync_field")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description = "MES上辅机采集字段映射")
public class MesXslMcsSyncField implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
private String id;
@Schema(description = "采集配置ID")
private String configId;
@Schema(description = "中间库源字段名")
private String sourceField;
@Schema(description = "源字段注释")
private String sourceFieldComment;
@Schema(description = "源字段类型")
private String sourceFieldType;
@Schema(description = "MES目标字段名(接收字段)")
private String targetField;
@Schema(description = "MES目标字段注释")
private String targetFieldComment;
@Schema(description = "是否匹配键(0否,1是)")
private String matchKey;
@Schema(description = "排序")
private Integer sortNo;
@Schema(description = "租户ID")
private Integer tenantId;
private String createBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private Integer delFlag;
}

View File

@@ -0,0 +1,58 @@
package org.jeecg.modules.xslmes.mcs.mapper;
import com.baomidou.dynamic.datasource.annotation.DS;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* 中间库(SQL Server) / MES(MySQL) 表与字段元数据查询。
* <p>源表元数据走 sqlserver_mcs 数据源,目标表元数据走默认 MES 库。</p>
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】采集配置-表与字段绑定
*/
public interface McsMetaMapper {
/**
* 中间库表清单(含表注释 MS_Description
*/
@DS("sqlserver_mcs")
@Select("SELECT t.name AS tableName, CAST(ep.value AS NVARCHAR(200)) AS tableComment "
+ "FROM sys.tables t "
+ "LEFT JOIN sys.extended_properties ep ON ep.major_id = t.object_id AND ep.minor_id = 0 AND ep.name = 'MS_Description' "
+ "ORDER BY t.name")
List<Map<String, Object>> listSourceTables();
/**
* 中间库表字段清单(含字段注释、类型)
*/
@DS("sqlserver_mcs")
@Select("SELECT c.name AS columnName, ty.name AS dataType, CAST(ep.value AS NVARCHAR(200)) AS columnComment "
+ "FROM sys.columns c "
+ "JOIN sys.types ty ON c.user_type_id = ty.user_type_id "
+ "LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id AND ep.minor_id = c.column_id AND ep.name = 'MS_Description' "
+ "WHERE c.object_id = OBJECT_ID(#{table}) "
+ "ORDER BY c.column_id")
List<Map<String, Object>> listSourceColumns(@Param("table") String table);
/**
* MES 业务表清单(仅 mes_xsl_ 前缀)
*/
@Select("SELECT table_name AS tableName, table_comment AS tableComment "
+ "FROM information_schema.tables "
+ "WHERE table_schema = (SELECT DATABASE()) AND table_name LIKE 'mes\\_xsl\\_%' "
+ "ORDER BY table_name")
List<Map<String, Object>> listTargetTables();
/**
* MES 表字段清单(含字段注释、类型)
*/
@Select("SELECT column_name AS columnName, data_type AS dataType, column_comment AS columnComment "
+ "FROM information_schema.columns "
+ "WHERE table_schema = (SELECT DATABASE()) AND table_name = #{table} "
+ "ORDER BY ordinal_position")
List<Map<String, Object>> listTargetColumns(@Param("table") String table);
}

View File

@@ -0,0 +1,10 @@
package org.jeecg.modules.xslmes.mcs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
/**
* MES上辅机 SQL Server 中间库配置 Mapper
*/
public interface MesXslMcsDbConfigMapper extends BaseMapper<MesXslMcsDbConfig> {
}

View File

@@ -0,0 +1,13 @@
package org.jeecg.modules.xslmes.mcs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
/**
* MES上辅机 中间表采集配置 Mapper
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】密炼动作秒级采集
*/
public interface MesXslMcsSyncConfigMapper extends BaseMapper<MesXslMcsSyncConfig> {
}

View File

@@ -0,0 +1,13 @@
package org.jeecg.modules.xslmes.mcs.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
/**
* MES上辅机 采集字段映射 Mapper
*
* @author GHT
* @date 2026-06-17 for【MES上辅机】采集配置-表与字段绑定
*/
public interface MesXslMcsSyncFieldMapper extends BaseMapper<MesXslMcsSyncField> {
}

View File

@@ -0,0 +1,19 @@
package org.jeecg.modules.xslmes.mcs.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
import java.util.Map;
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipAlarmRecordVO;
/**
* 设备报警记录只读SQL Server MCSToMES_MixAlarm
*/
public interface IMesXslEquipAlarmRecordService {
IPage<MesXslEquipAlarmRecordVO> queryPage(McsToMesMixAlarm query, Map<String, String[]> paramMap, int pageNo, int pageSize);
MesXslEquipAlarmRecordVO queryById(String id);
List<MesXslEquipAlarmRecordVO> listForExport(McsToMesMixAlarm query, Map<String, String[]> paramMap);
}

View File

@@ -0,0 +1,19 @@
package org.jeecg.modules.xslmes.mcs.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.util.List;
import java.util.Map;
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipDowntimeRecordVO;
/**
* 设备停机记录只读SQL Server MCSToMES_MixAlarm
*/
public interface IMesXslEquipDowntimeRecordService {
IPage<MesXslEquipDowntimeRecordVO> queryPage(McsToMesMixAlarm query, Map<String, String[]> paramMap, int pageNo, int pageSize);
MesXslEquipDowntimeRecordVO queryById(String id);
List<MesXslEquipDowntimeRecordVO> listForExport(McsToMesMixAlarm query, Map<String, String[]> paramMap);
}

Some files were not shown because too many files have changed in this diff Show More