Compare commits
29 Commits
c4447b91dd
...
20260519-3
| Author | SHA1 | Date | |
|---|---|---|---|
| 3bce685f3a | |||
| c54d54b40f | |||
|
|
a9b3720446 | ||
|
|
73a22b5ed9 | ||
| 372dc10be2 | |||
| 816af5df6e | |||
| 2ec2b6a628 | |||
| 7d7198b802 | |||
| 1c982052d3 | |||
| 94b15e5237 | |||
|
|
ba77a95554 | ||
|
|
e28352f8ea | ||
|
|
97a1543e97 | ||
|
|
d40a339aec | ||
|
|
54a132de46 | ||
|
|
c96833b339 | ||
|
|
9147e62977 | ||
| 380de8c54b | |||
| 7f0f8a3a2f | |||
|
|
44f9a3a197 | ||
|
|
276c808d7a | ||
| be215d604d | |||
|
|
33b969fc70 | ||
|
|
ece8e590e4 | ||
| 75bc744fc8 | |||
| 3431cc6b17 | |||
|
|
5cb24c582d | ||
|
|
617d47a3db | ||
| cbbbabe4cf |
67
.agents/skills/karpathy-guidelines/SKILL.md
Normal file
67
.agents/skills/karpathy-guidelines/SKILL.md
Normal 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
31
build-frontend.bat
Normal 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
26
build.bat
Normal 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
27
deploy-frontend.bat
Normal 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
36
deploy-server.bat
Normal 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
|
||||||
282
docs/QH-MES部署与热部署方案.md
Normal file
282
docs/QH-MES部署与热部署方案.md
Normal 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
|
||||||
|
```
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
-- MES 设备报警记录、设备停机记录:菜单 + 导出按钮 + 租户 admin 授权(无 MySQL 业务表)
|
||||||
|
-- 权限前缀:mes:mes_xsl_equip_alarm_record:* / mes:mes_xsl_equip_downtime_record:*
|
||||||
|
-- 父菜单:设备管理;Flyway:V3.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`
|
||||||
|
);
|
||||||
79
jeecg-boot/db/mes-xsl-mixing-production-plan-menu.sql
Normal file
79
jeecg-boot/db/mes-xsl-mixing-production-plan-menu.sql
Normal 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';
|
||||||
78
jeecg-boot/db/mes-xsl-raw-material-demand-plan-menu.sql
Normal file
78
jeecg-boot/db/mes-xsl-raw-material-demand-plan-menu.sql
Normal 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';
|
||||||
76
jeecg-boot/db/mes-xsl-small-material-demand-plan-menu.sql
Normal file
76
jeecg-boot/db/mes-xsl-small-material-demand-plan-menu.sql
Normal 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';
|
||||||
75
jeecg-boot/db/mes-xsl-small-material-plan-maintain-menu.sql
Normal file
75
jeecg-boot/db/mes-xsl-small-material-plan-maintain-menu.sql
Normal 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';
|
||||||
@@ -217,6 +217,12 @@ public class ShiroConfig {
|
|||||||
filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon");
|
filterChainDefinitionMap.put("/xslmes/mesXslUnit/anon/**", "anon");
|
||||||
// MES密炼物料管理免密接口(供桌面端调用)
|
// MES密炼物料管理免密接口(供桌面端调用)
|
||||||
filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon");
|
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/template/anon/**", "anon");
|
||||||
filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon");
|
filterChainDefinitionMap.put("/print/bizTemplateBind/anon/**", "anon");
|
||||||
|
|||||||
@@ -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
|
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
|
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温度条件新增是否附加/重量字段 -----
|
-- 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-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
|
jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslMixingSpecTcu.java
|
||||||
@@ -993,3 +1034,149 @@ 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/MesXslEquipPartMappingList.vue
|
||||||
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMapping.data.ts
|
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMapping.data.ts
|
||||||
jeecgboot-vue3/src/views/xslmes/mesXslEquipPartMapping/MesXslEquipPartMapping.api.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上辅机】采集模式:全量/时间/增量 + 批量增量写入(应对大表) ---
|
||||||
|
背景:原通用引擎每周期全表读源+全表读目标逐行Upsert,autocommit逐行往返,大表(上万~数十万)采集慢。
|
||||||
|
优化: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上辅机】采集模式:全量/时间/增量 + 批量增量写入(应对大表) ---
|
||||||
|
|||||||
@@ -133,24 +133,18 @@ public class ApprovalCallbackDispatcher {
|
|||||||
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());
|
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
switch (ctx.getAction()) {
|
//update-begin---author:cursor ---date:20260615 for:【XSLMES-20260615-A05】审批回调分发改用if-else,避免调试热更新缺失switch合成类-----------
|
||||||
case NODE_APPROVED:
|
ApprovalCallbackContext.Action action = ctx.getAction();
|
||||||
cb.onNodeApproved(ctx);
|
if (action == ApprovalCallbackContext.Action.NODE_APPROVED) {
|
||||||
break;
|
cb.onNodeApproved(ctx);
|
||||||
case APPROVED:
|
} else if (action == ApprovalCallbackContext.Action.APPROVED) {
|
||||||
cb.onApproved(ctx);
|
cb.onApproved(ctx);
|
||||||
break;
|
} else if (action == ApprovalCallbackContext.Action.REJECTED) {
|
||||||
case REJECTED:
|
cb.onRejected(ctx);
|
||||||
cb.onRejected(ctx);
|
} else if (action == ApprovalCallbackContext.Action.CANCELLED) {
|
||||||
break;
|
cb.onCancelled(ctx);
|
||||||
//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-end---author:cursor ---date:20260615 for:【XSLMES-20260615-A05】审批回调分发改用if-else,避免调试热更新缺失switch合成类-----------
|
||||||
if (dingTalk) {
|
if (dingTalk) {
|
||||||
log.info("{} 业务回调完成 {} action={} bizTable={} bizDataId={}",
|
log.info("{} 业务回调完成 {} action={} bizTable={} bizDataId={}",
|
||||||
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());
|
DING_LOG_TAG, callbackName, ctx.getAction(), ctx.getBizTable(), ctx.getBizDataId());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import org.jeecg.modules.xslmes.approval.callback.IApprovalBizCallback;
|
|||||||
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
|
import org.jeecg.modules.xslmes.common.XslMesBizConstants;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestStdService;
|
||||||
|
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,9 +26,13 @@ import org.springframework.stereotype.Component;
|
|||||||
public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback {
|
public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback {
|
||||||
|
|
||||||
private final IMesXslRubberQuickTestStdService stdService;
|
private final IMesXslRubberQuickTestStdService stdService;
|
||||||
|
private final MesXslStompNotifyService stompNotify;
|
||||||
|
|
||||||
public RubberQuickTestStdApprovalCallback(IMesXslRubberQuickTestStdService stdService) {
|
public RubberQuickTestStdApprovalCallback(
|
||||||
|
IMesXslRubberQuickTestStdService stdService,
|
||||||
|
MesXslStompNotifyService stompNotify) {
|
||||||
this.stdService = stdService;
|
this.stdService = stdService;
|
||||||
|
this.stompNotify = stompNotify;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -55,5 +60,8 @@ public class RubberQuickTestStdApprovalCallback implements IApprovalBizCallback
|
|||||||
.eq(MesXslRubberQuickTestStd::getId, bizDataId)
|
.eq(MesXslRubberQuickTestStd::getId, bizDataId)
|
||||||
.set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus)
|
.set(MesXslRubberQuickTestStd::getAuditStatus, auditStatus)
|
||||||
.update();
|
.update();
|
||||||
|
//update-begin---author:jiangxh ---date:20260617 for:【快检实验标准】审批联动 STOMP 同步桌面端-----------
|
||||||
|
stompNotify.publishRubberQuickTestStdChanged("audit", bizDataId);
|
||||||
|
//update-end---author:jiangxh ---date:20260617 for:【快检实验标准】审批联动 STOMP 同步桌面端-----------
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,4 +108,20 @@ public class MesXslApprovalHandleController {
|
|||||||
return Result.OK(approvalHandleService.pendingList(user));
|
return Result.OK(approvalHandleService.pendingList(user));
|
||||||
}
|
}
|
||||||
//update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流完善】待办列表-----
|
//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审批卡片(历史流转中实例)-----------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.service.IMesXslApprovalInstanceService;
|
||||||
import org.jeecg.modules.xslmes.approval.vo.ApprovalGateVo;
|
import org.jeecg.modules.xslmes.approval.vo.ApprovalGateVo;
|
||||||
import org.jeecg.modules.xslmes.common.MesXslTenantUtils;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -61,19 +63,37 @@ public class MesXslApprovalLaunchController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private JdbcTemplate jdbcTemplate;
|
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 = "发起审批-已发布审批流列表")
|
@Operation(summary = "发起审批-已发布审批流列表")
|
||||||
@GetMapping("/publishedList")
|
@GetMapping("/publishedList")
|
||||||
public Result<List<MesXslApprovalFlow>> publishedList() {
|
public Result<List<MesXslApprovalFlow>> publishedList(
|
||||||
|
@RequestParam(name = "routePath", required = false) String routePath) {
|
||||||
QueryWrapper<MesXslApprovalFlow> qw = new QueryWrapper<>();
|
QueryWrapper<MesXslApprovalFlow> qw = new QueryWrapper<>();
|
||||||
qw.eq("status", "1");
|
qw.eq("status", "1");
|
||||||
Integer tenantId = MesXslTenantUtils.resolveTenantId(null);
|
Integer tenantId = MesXslTenantUtils.resolveTenantId(null);
|
||||||
if (tenantId != null) {
|
if (tenantId != null) {
|
||||||
qw.eq("tenant_id", tenantId);
|
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");
|
qw.orderByDesc("create_time");
|
||||||
List<MesXslApprovalFlow> list = approvalFlowService.list(qw);
|
List<MesXslApprovalFlow> list = approvalFlowService.list(qw);
|
||||||
// 未手工指定 route_path 时,按单据表名自动反查菜单路由
|
// 未手工指定 route_path 时,按单据表名自动反查菜单路由
|
||||||
@@ -90,6 +110,59 @@ public class MesXslApprovalLaunchController {
|
|||||||
* 约定:jeecg 代码生成的列表组件名为 表名驼峰 + List(如 mes_xsl_formula_spec -> MesXslFormulaSpecList),
|
* 约定:jeecg 代码生成的列表组件名为 表名驼峰 + List(如 mes_xsl_formula_spec -> MesXslFormulaSpecList),
|
||||||
* 对应 sys_permission.component 形如 xslmes/mesXslFormulaSpec/MesXslFormulaSpecList,取其 url 即路由。
|
* 对应 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) {
|
private String resolveRoutePathByTable(String table) {
|
||||||
if (oConvertUtils.isEmpty(table) || !IDENTIFIER.matcher(table).matches()) {
|
if (oConvertUtils.isEmpty(table) || !IDENTIFIER.matcher(table).matches()) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -57,6 +57,14 @@ public interface IMesXslApprovalHandleService {
|
|||||||
Result<String> urge(String instanceId, LoginUser user);
|
Result<String> urge(String instanceId, LoginUser user);
|
||||||
//update-end---author:GHT ---date:2026-05-29 for:【QH-MES审批流完善】催办接口-----
|
//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审批流完善】待办列表查询-----
|
//update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流完善】待办列表查询-----
|
||||||
/**
|
/**
|
||||||
* 查询当前用户的待办审批列表(状态为审批中且当前处理人包含该用户)。
|
* 查询当前用户的待办审批列表(状态为审批中且当前处理人包含该用户)。
|
||||||
|
|||||||
@@ -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.entity.MesXslIntegrationPlan;
|
||||||
import org.jeecg.modules.xslmes.approval.integration.service.IMesXslIntegrationPlanService;
|
import org.jeecg.modules.xslmes.approval.integration.service.IMesXslIntegrationPlanService;
|
||||||
import org.jeecg.modules.xslmes.approval.service.IMesXslApprovalInstanceService;
|
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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@@ -100,6 +101,11 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslIntegrationPlanService integrationPlanService;
|
private IMesXslIntegrationPlanService integrationPlanService;
|
||||||
//update-end---author:GHT ---date:20260605 for:【XSLMES-20260605-K8R2】驳回回退改由集成方案 onReject 驱动-----------
|
//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审批流设计】审批与业务单据联动回调-----
|
//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);
|
oConvertUtils.getString(inst.getApplyUserName(), inst.getApplyUser()), inst.getFlowName(), actionLabel);
|
||||||
msgType = "text";
|
msgType = "text";
|
||||||
}
|
}
|
||||||
SysUser applicant = getUserSafely(inst.getApplyUser());
|
//update-begin---author:GHT ---date:20260610 for:【IM审批通用化】待办卡片由系统账号发给处理人,支持发起人=处理人-----------
|
||||||
String fromId = applicant == null ? null : applicant.getId();
|
|
||||||
for (String uname : handlerUsernames) {
|
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) */
|
/** 构建 biz_record 卡片 JSON(含 instanceId / actionLabel / canApprove,与前端 ImBizRecordPayload 对齐 v=2) */
|
||||||
private String buildCardJson(MesXslApprovalInstance inst, String actionLabel, boolean canApprove, String routePath) {
|
private String buildCardJson(MesXslApprovalInstance inst, String actionLabel, boolean canApprove, String routePath) {
|
||||||
//update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流设计】区分审批卡片与抄送通知卡片-----
|
//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) {
|
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-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();
|
JSONArray fields = new JSONArray();
|
||||||
addField(fields, "审批流", inst.getFlowName());
|
addField(fields, "审批流", inst.getFlowName());
|
||||||
addField(fields, "单据", safeTitle(inst));
|
addField(fields, "单据", safeTitle(inst));
|
||||||
@@ -1353,10 +1386,26 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
|
|||||||
if (user != null) {
|
if (user != null) {
|
||||||
ctx.setOperatorUsername(user.getUsername());
|
ctx.setOperatorUsername(user.getUsername());
|
||||||
ctx.setOperatorName(oConvertUtils.getString(user.getRealname(), user.getUsername()));
|
ctx.setOperatorName(oConvertUtils.getString(user.getRealname(), user.getUsername()));
|
||||||
|
ctx.setOperatorTime(new Date());
|
||||||
} else {
|
} else {
|
||||||
ctx.setOperatorUsername("system");
|
ctx.setOperatorUsername("system");
|
||||||
ctx.setOperatorName("系统");
|
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;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1455,7 +1504,7 @@ public class MesXslApprovalHandleServiceImpl implements IMesXslApprovalHandleSer
|
|||||||
if (oConvertUtils.isEmpty(uname)) {
|
if (oConvertUtils.isEmpty(uname)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sendOne(user.getId(), uname, inst.getTenantId(),
|
sendApprovalHandlerNotify(uname, inst.getTenantId(),
|
||||||
"【催办提醒】" + applicantName + " 催促您处理「" + safeTitle(inst) + "」,请尽快审批。", "text");
|
"【催办提醒】" + applicantName + " 催促您处理「" + safeTitle(inst) + "」,请尽快审批。", "text");
|
||||||
}
|
}
|
||||||
urgeTimeMap.put(instanceId, System.currentTimeMillis());
|
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-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审批流完善】待办列表:查询当前用户的待处理审批实例-----
|
//update-begin---author:GHT ---date:2026-05-29 for:【QH-MES审批流完善】待办列表:查询当前用户的待处理审批实例-----
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ import java.util.Set;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpec;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslFormulaSpecLine;
|
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.MesXslFormulaSpecEditChangeItemVO;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
||||||
|
|
||||||
@@ -82,6 +86,35 @@ public final class MesXslFormulaSpecEditLogDiffUtil {
|
|||||||
return toJson(snapshot);
|
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(
|
public static List<MesXslFormulaSpecEditChangeItemVO> compare(
|
||||||
String specType, String beforeSnapshot, String afterSnapshot) {
|
String specType, String beforeSnapshot, String afterSnapshot) {
|
||||||
List<MesXslFormulaSpecEditChangeItemVO> items = new ArrayList<>();
|
List<MesXslFormulaSpecEditChangeItemVO> items = new ArrayList<>();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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("保存成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jeecg.modules.xslmes.controller;
|
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.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
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.IPrintBizTemplateBindService;
|
||||||
import org.jeecg.modules.print.service.IPrintTemplateService;
|
import org.jeecg.modules.print.service.IPrintTemplateService;
|
||||||
import org.jeecg.modules.print.util.PrintBizDataMappingUtil;
|
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.MesXslCustomerBizStatus;
|
||||||
import org.jeecg.modules.xslmes.constant.MesXslPrintConstants;
|
import org.jeecg.modules.xslmes.constant.MesXslPrintConstants;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslCustomer;
|
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.MesXslVehicle;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
|
import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslWarehouseArea;
|
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.entity.MesXslWeightRecord;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
|
import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService;
|
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialCardService;
|
||||||
@@ -42,6 +50,10 @@ import org.jeecg.modules.xslmes.service.IMesXslUnitService;
|
|||||||
import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
|
import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService;
|
import org.jeecg.modules.xslmes.service.IMesXslWarehouseAreaService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslWarehouseService;
|
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.IMesXslWeightRecordService;
|
||||||
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
|
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO;
|
import org.jeecg.modules.xslmes.vo.MesXslRawMaterialCardBriefVO;
|
||||||
@@ -87,6 +99,10 @@ public class MesXslDesktopAnonController {
|
|||||||
private final IPrintBizTemplateBindService printBizTemplateBindService;
|
private final IPrintBizTemplateBindService printBizTemplateBindService;
|
||||||
private final IPrintTemplateService printTemplateService;
|
private final IPrintTemplateService printTemplateService;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
private final IMesXslMixingProductionPlanService mixingProductionPlanService;
|
||||||
|
private final IMesXslRubberQuickTestStdService rubberQuickTestStdService;
|
||||||
|
private final IMesXslRubberQuickTestRecordService rubberQuickTestRecordService;
|
||||||
|
private final IMesXslRubberQuickTestMethodService rubberQuickTestMethodService;
|
||||||
|
|
||||||
// ═══════════════════════════ 车辆管理 ═══════════════════════════
|
// ═══════════════════════════ 车辆管理 ═══════════════════════════
|
||||||
|
|
||||||
@@ -925,6 +941,128 @@ public class MesXslDesktopAnonController {
|
|||||||
}
|
}
|
||||||
//update-end---author:cursor ---date:20250602 for:【密炼物料皮重策略】桌面端单位下拉只读-----------
|
//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 = "胶料快检记录-免密添加")
|
||||||
|
@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("胶料名称不能为空");
|
||||||
|
}
|
||||||
|
List<MesXslRubberQuickTestRecordLine> lineList = record.getLineList();
|
||||||
|
if (lineList == null || lineList.isEmpty()) {
|
||||||
|
return Result.error("请维护检验明细");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (oConvertUtils.isEmpty(record.getRecordNo())) {
|
||||||
|
record.setRecordNo(rubberQuickTestRecordService.generateDesktopRecordNo(record));
|
||||||
|
}
|
||||||
|
rubberQuickTestRecordService.fillQuickTestTypeForRecord(record);
|
||||||
|
rubberQuickTestRecordService.saveMain(record, lineList);
|
||||||
|
stompNotify.publishRubberQuickTestRecordChanged("add", record.getId());
|
||||||
|
return Result.OK(record.getRecordNo());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
return Result.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//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) {
|
private void applyWeightNetAndBillType(MesXslWeightRecord record) {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
|
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
|
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.IMesXslDowntimeMainTypeService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
@@ -53,6 +54,9 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslProcessOperationService mesXslProcessOperationService;
|
private IMesXslProcessOperationService mesXslProcessOperationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES停机主类型-分页列表查询")
|
@Operation(summary = "MES停机主类型-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslDowntimeMainType>> queryPageList(
|
public Result<IPage<MesXslDowntimeMainType>> queryPageList(
|
||||||
@@ -104,6 +108,10 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
|
|||||||
@RequiresPermissions("mes:mes_xsl_downtime_main_type:delete")
|
@RequiresPermissions("mes:mes_xsl_downtime_main_type:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslDowntimeMainTypeService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -113,6 +121,10 @@ public class MesXslDowntimeMainTypeController extends JeecgController<MesXslDown
|
|||||||
@RequiresPermissions("mes:mes_xsl_downtime_main_type:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_downtime_main_type:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslDowntimeMainTypeService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
|
import org.jeecg.modules.xslmes.entity.MesXslDowntimeMainType;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslDowntimeType;
|
import org.jeecg.modules.xslmes.entity.MesXslDowntimeType;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
|
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.IMesXslDowntimeMainTypeService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslDowntimeTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslDowntimeTypeService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
||||||
@@ -59,6 +60,9 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslDowntimeMainTypeService mesXslDowntimeMainTypeService;
|
private IMesXslDowntimeMainTypeService mesXslDowntimeMainTypeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES停机类型-分页列表查询")
|
@Operation(summary = "MES停机类型-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslDowntimeType>> queryPageList(
|
public Result<IPage<MesXslDowntimeType>> queryPageList(
|
||||||
@@ -110,6 +114,10 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
|
|||||||
@RequiresPermissions("mes:mes_xsl_downtime_type:delete")
|
@RequiresPermissions("mes:mes_xsl_downtime_type:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslDowntimeTypeService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -119,6 +127,10 @@ public class MesXslDowntimeTypeController extends JeecgController<MesXslDowntime
|
|||||||
@RequiresPermissions("mes:mes_xsl_downtime_type:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_downtime_type:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslDowntimeTypeService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import org.jeecg.modules.xslmes.entity.MesXslEquipInspectConfig;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipInspectConfigLine;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipInspectConfigLine;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslInspectMaintainItem;
|
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.IMesXslEquipInspectConfigService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
|
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
|
||||||
@@ -53,6 +54,9 @@ public class MesXslEquipInspectConfigController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslInspectMaintainItemService mesXslInspectMaintainItemService;
|
private IMesXslInspectMaintainItemService mesXslInspectMaintainItemService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备点检配置-分页列表查询")
|
@Operation(summary = "MES设备点检配置-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipInspectConfig>> queryPageList(
|
public Result<IPage<MesXslEquipInspectConfig>> queryPageList(
|
||||||
@@ -106,6 +110,10 @@ public class MesXslEquipInspectConfigController
|
|||||||
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:delete")
|
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipInspectConfigService.delMain(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -115,6 +123,10 @@ public class MesXslEquipInspectConfigController
|
|||||||
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equip_inspect_config:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipInspectConfigService.delBatchMain(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
|
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.IMesXslEquipmentCategoryService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
@@ -52,6 +53,9 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslProcessOperationService mesXslProcessOperationService;
|
private IMesXslProcessOperationService mesXslProcessOperationService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备类别-分页列表查询")
|
@Operation(summary = "MES设备类别-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipmentCategory>> queryPageList(
|
public Result<IPage<MesXslEquipmentCategory>> queryPageList(
|
||||||
@@ -100,6 +104,10 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_category:delete")
|
@RequiresPermissions("mes:mes_xsl_equipment_category:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipmentCategoryService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -109,6 +117,10 @@ public class MesXslEquipmentCategoryController extends JeecgController<MesXslEqu
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_category:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equipment_category:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipmentCategoryService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
|
|||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentLedger;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentLedgerService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
@@ -45,6 +46,9 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslEquipmentLedgerService mesXslEquipmentLedgerService;
|
private IMesXslEquipmentLedgerService mesXslEquipmentLedgerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备台账-分页列表查询")
|
@Operation(summary = "MES设备台账-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipmentLedger>> queryPageList(
|
public Result<IPage<MesXslEquipmentLedger>> queryPageList(
|
||||||
@@ -96,6 +100,10 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_ledger:delete")
|
@RequiresPermissions("mes:mes_xsl_equipment_ledger:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipmentLedgerService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -105,6 +113,10 @@ public class MesXslEquipmentLedgerController extends JeecgController<MesXslEquip
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_ledger:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equipment_ledger:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipmentLedgerService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentPart;
|
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.IMesXslEquipmentCategoryService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
@@ -49,6 +50,9 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
|
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备部位-分页列表查询")
|
@Operation(summary = "MES设备部位-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipmentPart>> queryPageList(
|
public Result<IPage<MesXslEquipmentPart>> queryPageList(
|
||||||
@@ -97,6 +101,10 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_part:delete")
|
@RequiresPermissions("mes:mes_xsl_equipment_part:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipmentPartService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -106,6 +114,10 @@ public class MesXslEquipmentPartController extends JeecgController<MesXslEquipme
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_part:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equipment_part:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipmentPartService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentPart;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentPart;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentSubPart;
|
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.IMesXslEquipmentCategoryService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentPartService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
|
||||||
@@ -54,6 +55,9 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslEquipmentPartService mesXslEquipmentPartService;
|
private IMesXslEquipmentPartService mesXslEquipmentPartService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备小部位-分页列表查询")
|
@Operation(summary = "MES设备小部位-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipmentSubPart>> queryPageList(
|
public Result<IPage<MesXslEquipmentSubPart>> queryPageList(
|
||||||
@@ -102,6 +106,10 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:delete")
|
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipmentSubPartService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -111,6 +119,10 @@ public class MesXslEquipmentSubPartController extends JeecgController<MesXslEqui
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equipment_sub_part:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipmentSubPartService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentCategory;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslEquipmentType;
|
import org.jeecg.modules.xslmes.entity.MesXslEquipmentType;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslProcessOperation;
|
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.IMesXslEquipmentCategoryService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
import org.jeecg.modules.xslmes.service.IMesXslProcessOperationService;
|
||||||
@@ -54,6 +55,9 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
|
private IMesXslEquipmentCategoryService mesXslEquipmentCategoryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES设备类型-分页列表查询")
|
@Operation(summary = "MES设备类型-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslEquipmentType>> queryPageList(
|
public Result<IPage<MesXslEquipmentType>> queryPageList(
|
||||||
@@ -102,6 +106,10 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_type:delete")
|
@RequiresPermissions("mes:mes_xsl_equipment_type:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslEquipmentTypeService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -111,6 +119,10 @@ public class MesXslEquipmentTypeController extends JeecgController<MesXslEquipme
|
|||||||
@RequiresPermissions("mes:mes_xsl_equipment_type:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_equipment_type:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslEquipmentTypeService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
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.IMesXslEquipmentPartService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentSubPartService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslEquipmentTypeService;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
|
import org.jeecg.modules.xslmes.service.IMesXslInspectMaintainItemService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -60,6 +62,9 @@ public class MesXslInspectMaintainItemController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslEquipmentSubPartService mesXslEquipmentSubPartService;
|
private IMesXslEquipmentSubPartService mesXslEquipmentSubPartService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES点检及保养项目-分页列表查询")
|
@Operation(summary = "MES点检及保养项目-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslInspectMaintainItem>> queryPageList(
|
public Result<IPage<MesXslInspectMaintainItem>> queryPageList(
|
||||||
@@ -109,6 +114,12 @@ public class MesXslInspectMaintainItemController
|
|||||||
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:delete")
|
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslInspectMaintainItemService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -118,6 +129,12 @@ public class MesXslInspectMaintainItemController
|
|||||||
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_inspect_maintain_item:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslInspectMaintainItemService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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("保存成功");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
|
|||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslManufacturer;
|
import org.jeecg.modules.xslmes.entity.MesXslManufacturer;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslManufacturerService;
|
import org.jeecg.modules.xslmes.service.IMesXslManufacturerService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
@@ -45,6 +46,9 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslManufacturerService mesXslManufacturerService;
|
private IMesXslManufacturerService mesXslManufacturerService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES厂家信息-分页列表查询")
|
@Operation(summary = "MES厂家信息-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslManufacturer>> queryPageList(
|
public Result<IPage<MesXslManufacturer>> queryPageList(
|
||||||
@@ -93,6 +97,10 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
|
|||||||
@RequiresPermissions("mes:mes_xsl_manufacturer:delete")
|
@RequiresPermissions("mes:mes_xsl_manufacturer:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslManufacturerService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -102,6 +110,10 @@ public class MesXslManufacturerController extends JeecgController<MesXslManufact
|
|||||||
@RequiresPermissions("mes:mes_xsl_manufacturer:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_manufacturer:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslManufacturerService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,13 +112,14 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
|
|||||||
@Operation(summary = "校验动作名称是否重复")
|
@Operation(summary = "校验动作名称是否重复")
|
||||||
@GetMapping("/checkActionName")
|
@GetMapping("/checkActionName")
|
||||||
public Result<String> checkActionName(
|
public Result<String> checkActionName(
|
||||||
|
@RequestParam(name = "equipmentId", required = false) String equipmentId,
|
||||||
@RequestParam(name = "actionName", required = true) String actionName,
|
@RequestParam(name = "actionName", required = true) String actionName,
|
||||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||||
if (oConvertUtils.isEmpty(actionName) || actionName.trim().isEmpty()) {
|
if (oConvertUtils.isEmpty(actionName) || actionName.trim().isEmpty()) {
|
||||||
return Result.OK("该值可用!");
|
return Result.OK("该值可用!");
|
||||||
}
|
}
|
||||||
if (mesXslMixerActionService.isActionNameDuplicated(actionName, dataId)) {
|
if (mesXslMixerActionService.isActionNameDuplicated(equipmentId, actionName, dataId)) {
|
||||||
return Result.error("动作名称不能重复");
|
return Result.error("同一设备下动作名称不能重复");
|
||||||
}
|
}
|
||||||
return Result.OK("该值可用!");
|
return Result.OK("该值可用!");
|
||||||
}
|
}
|
||||||
@@ -126,13 +127,14 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
|
|||||||
@Operation(summary = "校验动作代号是否重复")
|
@Operation(summary = "校验动作代号是否重复")
|
||||||
@GetMapping("/checkActionCode")
|
@GetMapping("/checkActionCode")
|
||||||
public Result<String> checkActionCode(
|
public Result<String> checkActionCode(
|
||||||
|
@RequestParam(name = "equipmentId", required = false) String equipmentId,
|
||||||
@RequestParam(name = "actionCode", required = true) String actionCode,
|
@RequestParam(name = "actionCode", required = true) String actionCode,
|
||||||
@RequestParam(name = "dataId", required = false) String dataId) {
|
@RequestParam(name = "dataId", required = false) String dataId) {
|
||||||
if (oConvertUtils.isEmpty(actionCode) || actionCode.trim().isEmpty()) {
|
if (oConvertUtils.isEmpty(actionCode) || actionCode.trim().isEmpty()) {
|
||||||
return Result.OK("该值可用!");
|
return Result.OK("该值可用!");
|
||||||
}
|
}
|
||||||
if (mesXslMixerActionService.isActionCodeDuplicated(actionCode, dataId)) {
|
if (mesXslMixerActionService.isActionCodeDuplicated(equipmentId, actionCode, dataId)) {
|
||||||
return Result.error("动作代号不能重复");
|
return Result.error("同一设备下动作代号不能重复");
|
||||||
}
|
}
|
||||||
return Result.OK("该值可用!");
|
return Result.OK("该值可用!");
|
||||||
}
|
}
|
||||||
@@ -152,15 +154,15 @@ public class MesXslMixerActionController extends JeecgController<MesXslMixerActi
|
|||||||
return "动作名称不能为空";
|
return "动作名称不能为空";
|
||||||
}
|
}
|
||||||
model.setActionName(model.getActionName().trim());
|
model.setActionName(model.getActionName().trim());
|
||||||
if (mesXslMixerActionService.isActionNameDuplicated(model.getActionName(), excludeId)) {
|
if (mesXslMixerActionService.isActionNameDuplicated(model.getEquipmentId(), model.getActionName(), excludeId)) {
|
||||||
return "动作名称不能重复";
|
return "同一设备下动作名称不能重复";
|
||||||
}
|
}
|
||||||
if (oConvertUtils.isEmpty(model.getActionCode()) || StringUtils.isBlank(model.getActionCode())) {
|
if (oConvertUtils.isEmpty(model.getActionCode()) || StringUtils.isBlank(model.getActionCode())) {
|
||||||
return "动作代号不能为空";
|
return "动作代号不能为空";
|
||||||
}
|
}
|
||||||
model.setActionCode(model.getActionCode().trim());
|
model.setActionCode(model.getActionCode().trim());
|
||||||
if (mesXslMixerActionService.isActionCodeDuplicated(model.getActionCode(), excludeId)) {
|
if (mesXslMixerActionService.isActionCodeDuplicated(model.getEquipmentId(), model.getActionCode(), excludeId)) {
|
||||||
return "动作代号不能重复";
|
return "同一设备下动作代号不能重复";
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import org.jeecg.common.util.oConvertUtils;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
import org.jeecg.modules.xslmes.entity.MesXslMixingSpec;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
import org.jeecg.modules.xslmes.service.IMesXslMixingSpecService;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecPage;
|
||||||
|
import org.jeecg.modules.xslmes.vo.MesXslMixingSpecSmallWeighRangeVO;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -175,6 +176,17 @@ public class MesXslMixingSpecController extends JeecgController<MesXslMixingSpec
|
|||||||
return Result.OK(mesXslMixingSpecService.queryPurposeOptions(keyword));
|
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")
|
@RequiresPermissions("xslmes:mes_xsl_mixing_spec:exportXls")
|
||||||
@RequestMapping(value = "/exportXls")
|
@RequestMapping(value = "/exportXls")
|
||||||
public ModelAndView exportXls(HttpServletRequest request, MesXslMixingSpec model) {
|
public ModelAndView exportXls(HttpServletRequest request, MesXslMixingSpec model) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||||
@@ -97,9 +98,19 @@ public class MesXslProductionOrderController
|
|||||||
@Operation(summary = "生产订单-拆分生成母胶计划")
|
@Operation(summary = "生产订单-拆分生成母胶计划")
|
||||||
@RequiresPermissions("xslmes:mes_xsl_production_order:split")
|
@RequiresPermissions("xslmes:mes_xsl_production_order:split")
|
||||||
@PostMapping("/split")
|
@PostMapping("/split")
|
||||||
public Result<MesXslMasterBatchPlan> split(@RequestParam(name = "id", required = true) String id) {
|
public Result<List<MesXslMasterBatchPlan>> split(@RequestParam(name = "id", required = true) String id) {
|
||||||
MesXslMasterBatchPlan plan = mesXslProductionOrderService.splitToMasterBatchPlan(id);
|
List<MesXslMasterBatchPlan> plans = mesXslProductionOrderService.splitToMasterBatchPlan(id);
|
||||||
return Result.OK("拆分成功", plan);
|
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")
|
@RequiresPermissions("xslmes:mes_xsl_production_order:exportXls")
|
||||||
|
|||||||
@@ -0,0 +1,178 @@
|
|||||||
|
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 machineExpr = "COALESCE(NULLIF(TRIM(t.machine_name),''), '')";
|
||||||
|
String erpCodeExpr = "COALESCE(NULLIF(TRIM(t.erp_code),''), '')";
|
||||||
|
String rawMaterialExpr = "COALESCE(NULLIF(TRIM(t.raw_material_name),''), '')";
|
||||||
|
|
||||||
|
StringBuilder sql = new StringBuilder();
|
||||||
|
sql.append("SELECT ");
|
||||||
|
if (groupedByMachine) {
|
||||||
|
sql.append(machineExpr).append(" AS machineName, ");
|
||||||
|
} else {
|
||||||
|
sql.append("'' AS machineName, ");
|
||||||
|
}
|
||||||
|
sql.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() + "%");
|
||||||
|
}
|
||||||
|
|
||||||
|
sql.append("GROUP BY ");
|
||||||
|
if (groupedByMachine) {
|
||||||
|
sql.append(machineExpr).append(", ");
|
||||||
|
}
|
||||||
|
sql.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.setMachineName(groupedByMachine ? trim(rs.getString("machineName")) : "");
|
||||||
|
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 machineName, rawMaterialName, erpCode";
|
||||||
|
}
|
||||||
|
return " ORDER BY rawMaterialName, erpCode";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildRowId(MesXslRawMaterialDemandPlanSummary row, boolean groupedByMachine, int seq) {
|
||||||
|
String machine = groupedByMachine ? StringUtils.defaultString(row.getMachineName()) : "ALL";
|
||||||
|
return machine + "_" + StringUtils.defaultString(row.getErpCode()) + "_" + seq;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trim(String value) {
|
||||||
|
return value == null ? "" : value.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestDataPoint;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestDataPoint;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
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.IMesXslRubberQuickTestDataPointService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
@@ -51,6 +52,9 @@ public class MesXslRubberQuickTestDataPointController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检数据点-分页列表查询")
|
@Operation(summary = "MES胶料快检数据点-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslRubberQuickTestDataPoint>> queryPageList(
|
public Result<IPage<MesXslRubberQuickTestDataPoint>> queryPageList(
|
||||||
@@ -120,6 +124,10 @@ public class MesXslRubberQuickTestDataPointController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:delete")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslRubberQuickTestDataPointService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -129,6 +137,10 @@ public class MesXslRubberQuickTestDataPointController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_data_point:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslRubberQuickTestDataPointService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
|||||||
|
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestDataPointService;
|
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.IMesXslRubberQuickTestMethodService;
|
||||||
|
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
||||||
@@ -102,7 +103,8 @@ public class MesXslRubberQuickTestMethodController
|
|||||||
|
|
||||||
private IMesXslRubberQuickTestDataPointService mesXslRubberQuickTestDataPointService;
|
private IMesXslRubberQuickTestDataPointService mesXslRubberQuickTestDataPointService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检实验方法-分页列表查询")
|
@Operation(summary = "MES胶料快检实验方法-分页列表查询")
|
||||||
|
|
||||||
@@ -231,29 +233,25 @@ public class MesXslRubberQuickTestMethodController
|
|||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
|
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslRubberQuickTestMethodService.delMain(id);
|
||||||
|
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@AutoLog(value = "MES胶料快检实验方法-批量删除")
|
@AutoLog(value = "MES胶料快检实验方法-批量删除")
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检实验方法-批量删除")
|
@Operation(summary = "MES胶料快检实验方法-批量删除")
|
||||||
|
|
||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_method:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_method:deleteBatch")
|
||||||
|
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
|
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslRubberQuickTestMethodService.delBatchMain(Arrays.asList(ids.split(",")));
|
||||||
|
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,15 @@ import org.jeecg.common.aspect.annotation.AutoLog;
|
|||||||
import org.jeecg.common.system.base.controller.JeecgController;
|
import org.jeecg.common.system.base.controller.JeecgController;
|
||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
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.entity.MesMaterial;
|
||||||
import org.jeecg.modules.mes.material.service.IMesMaterialService;
|
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.MesXslRubberQuickTestRecord;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordLine;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestRecordRawLine;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestRecordService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
||||||
@@ -49,6 +54,9 @@ public class MesXslRubberQuickTestRecordController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ISysUserService sysUserService;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检记录-分页列表查询")
|
@Operation(summary = "MES胶料快检记录-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslRubberQuickTestRecord>> queryPageList(
|
public Result<IPage<MesXslRubberQuickTestRecord>> queryPageList(
|
||||||
@@ -110,6 +118,9 @@ public class MesXslRubberQuickTestRecordController
|
|||||||
@PostMapping(value = "/batchFromMaterial")
|
@PostMapping(value = "/batchFromMaterial")
|
||||||
public Result<List<String>> batchFromMaterial(@RequestBody MesXslRubberQuickTestRecordBatchFromMaterialVO vo) {
|
public Result<List<String>> batchFromMaterial(@RequestBody MesXslRubberQuickTestRecordBatchFromMaterialVO vo) {
|
||||||
try {
|
try {
|
||||||
|
//update-begin---author:jiangxh ---date:20260616 for:【MES】胶料快检记录批量生成默认带出当前登录检验人-----------
|
||||||
|
fillInspectorIfEmpty(vo);
|
||||||
|
//update-end---author:jiangxh ---date:20260616 for:【MES】胶料快检记录批量生成默认带出当前登录检验人-----------
|
||||||
List<String> ids = mesXslRubberQuickTestRecordService.batchFromMaterial(vo);
|
List<String> ids = mesXslRubberQuickTestRecordService.batchFromMaterial(vo);
|
||||||
return Result.OK("成功生成 " + ids.size() + " 条快检记录", ids);
|
return Result.OK("成功生成 " + ids.size() + " 条快检记录", ids);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@@ -153,6 +164,15 @@ public class MesXslRubberQuickTestRecordController
|
|||||||
return Result.OK(mesXslRubberQuickTestRecordService.selectLinesByRecordId(id));
|
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:【快检记录】查询原始数据明细-----------
|
||||||
|
|
||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_record:exportXls")
|
||||||
@RequestMapping(value = "/exportXls")
|
@RequestMapping(value = "/exportXls")
|
||||||
public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) {
|
public ModelAndView exportXls(HttpServletRequest request, MesXslRubberQuickTestRecord model) {
|
||||||
@@ -186,6 +206,10 @@ public class MesXslRubberQuickTestRecordController
|
|||||||
main.setQuickTestTypeName(type.getTypeName());
|
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()) {
|
if (lineList == null || lineList.isEmpty()) {
|
||||||
return "请维护检验明细";
|
return "请维护检验明细";
|
||||||
}
|
}
|
||||||
@@ -197,4 +221,35 @@ public class MesXslRubberQuickTestRecordController
|
|||||||
}
|
}
|
||||||
return null;
|
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】胶料快检记录检验人冗余字段补全-----------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,9 @@ import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStd;
|
|||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestStdLine;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
|
import org.jeecg.modules.xslmes.service.IMesXslMixerPsCompileService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestMethodService;
|
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.IMesXslRubberQuickTestStdService;
|
||||||
|
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
|
||||||
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage;
|
import org.jeecg.modules.xslmes.vo.MesXslRubberQuickTestStdPage;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -69,6 +71,12 @@ public class MesXslRubberQuickTestStdController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysDepartService sysDepartService;
|
private ISysDepartService sysDepartService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslStompNotifyService stompNotify;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检实验标准-分页列表查询")
|
@Operation(summary = "MES胶料快检实验标准-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslRubberQuickTestStd>> queryPageList(
|
public Result<IPage<MesXslRubberQuickTestStd>> queryPageList(
|
||||||
@@ -103,6 +111,9 @@ public class MesXslRubberQuickTestStdController
|
|||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
return Result.error(e.getMessage());
|
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("添加成功!");
|
return Result.OK("添加成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +136,9 @@ public class MesXslRubberQuickTestStdController
|
|||||||
log.error(e.getMessage(), e);
|
log.error(e.getMessage(), e);
|
||||||
return Result.error(e.getMessage());
|
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("编辑成功!");
|
return Result.OK("编辑成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +147,14 @@ public class MesXslRubberQuickTestStdController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:delete")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
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("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +163,14 @@ public class MesXslRubberQuickTestStdController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_std:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
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("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +212,9 @@ public class MesXslRubberQuickTestStdController
|
|||||||
.set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus)
|
.set(MesXslRubberQuickTestStd::getEnableStatus, enableStatus)
|
||||||
.update();
|
.update();
|
||||||
if (updated) {
|
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("操作成功");
|
return Result.OK("操作成功");
|
||||||
}
|
}
|
||||||
MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id);
|
MesXslRubberQuickTestStd cur = mesXslRubberQuickTestStdService.getById(id);
|
||||||
@@ -226,13 +257,6 @@ public class MesXslRubberQuickTestStdController
|
|||||||
if (main == null) {
|
if (main == null) {
|
||||||
return "参数不能为空";
|
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())) {
|
if (oConvertUtils.isEmpty(main.getTestMethodId())) {
|
||||||
return "请选择实验方法";
|
return "请选择实验方法";
|
||||||
}
|
}
|
||||||
@@ -242,13 +266,22 @@ public class MesXslRubberQuickTestStdController
|
|||||||
}
|
}
|
||||||
main.setTestMethodName(method.getMethodName());
|
main.setTestMethodName(method.getMethodName());
|
||||||
|
|
||||||
if (oConvertUtils.isNotEmpty(main.getRubberMaterialId())) {
|
if (oConvertUtils.isEmpty(main.getRubberMaterialId())) {
|
||||||
MesMaterial material = mesMaterialService.getById(main.getRubberMaterialId());
|
return "请选择胶料信息";
|
||||||
if (material == null) {
|
|
||||||
return "所选胶料不存在";
|
|
||||||
}
|
|
||||||
main.setRubberMaterialName(material.getMaterialName());
|
|
||||||
}
|
}
|
||||||
|
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())) {
|
if (oConvertUtils.isNotEmpty(main.getPsCompileId())) {
|
||||||
MesXslMixerPsCompile ps = mesXslMixerPsCompileService.getById(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())) {
|
if (!XslMesBizConstants.PS_TYPE_RAW_INSPECT_STD.equals(ps.getPsType())) {
|
||||||
return "发行编号须选择类型为原材料检验标准的密炼PS";
|
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());
|
main.setIssueNumber(ps.getPsCode());
|
||||||
if (main.getIssueDate() == null && ps.getIssueDate() != null) {
|
if (main.getIssueDate() == null && ps.getIssueDate() != null) {
|
||||||
main.setIssueDate(ps.getIssueDate());
|
main.setIssueDate(ps.getIssueDate());
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.exception.JeecgBootException;
|
import org.jeecg.common.exception.JeecgBootException;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberQuickTestType;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberQuickTestTypeService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
@@ -44,6 +45,9 @@ public class MesXslRubberQuickTestTypeController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
private IMesXslRubberQuickTestTypeService mesXslRubberQuickTestTypeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料快检实验类型-分页列表查询")
|
@Operation(summary = "MES胶料快检实验类型-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslRubberQuickTestType>> queryPageList(
|
public Result<IPage<MesXslRubberQuickTestType>> queryPageList(
|
||||||
@@ -116,6 +120,10 @@ public class MesXslRubberQuickTestTypeController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:delete")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslRubberQuickTestTypeService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -125,6 +133,10 @@ public class MesXslRubberQuickTestTypeController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_rubber_quick_test_type:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslRubberQuickTestTypeService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.jeecg.common.system.query.QueryGenerator;
|
|||||||
import org.jeecg.common.constant.CommonConstant;
|
import org.jeecg.common.constant.CommonConstant;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslRubberSmallLockReason;
|
import org.jeecg.modules.xslmes.entity.MesXslRubberSmallLockReason;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslRubberSmallLockReasonService;
|
import org.jeecg.modules.xslmes.service.IMesXslRubberSmallLockReasonService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
@@ -44,6 +45,9 @@ public class MesXslRubberSmallLockReasonController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslRubberSmallLockReasonService mesXslRubberSmallLockReasonService;
|
private IMesXslRubberSmallLockReasonService mesXslRubberSmallLockReasonService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES胶料小料锁定原因-分页列表查询")
|
@Operation(summary = "MES胶料小料锁定原因-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslRubberSmallLockReason>> queryPageList(
|
public Result<IPage<MesXslRubberSmallLockReason>> queryPageList(
|
||||||
@@ -122,6 +126,10 @@ public class MesXslRubberSmallLockReasonController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:delete")
|
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslRubberSmallLockReasonService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -131,6 +139,10 @@ public class MesXslRubberSmallLockReasonController
|
|||||||
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_rubber_small_lock_reason:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslRubberSmallLockReasonService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.jeecg.common.system.base.controller.JeecgController;
|
|||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.common.util.oConvertUtils;
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.xslmes.entity.MesXslSparePartsCategory;
|
import org.jeecg.modules.xslmes.entity.MesXslSparePartsCategory;
|
||||||
|
import org.jeecg.modules.xslmes.service.IMesXslDeleteReferenceService;
|
||||||
import org.jeecg.modules.xslmes.service.IMesXslSparePartsCategoryService;
|
import org.jeecg.modules.xslmes.service.IMesXslSparePartsCategoryService;
|
||||||
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
import org.jeecgframework.poi.excel.ExcelImportUtil;
|
||||||
import org.jeecgframework.poi.excel.entity.ImportParams;
|
import org.jeecgframework.poi.excel.entity.ImportParams;
|
||||||
@@ -42,6 +43,9 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IMesXslSparePartsCategoryService mesXslSparePartsCategoryService;
|
private IMesXslSparePartsCategoryService mesXslSparePartsCategoryService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDeleteReferenceService mesXslDeleteReferenceService;
|
||||||
|
|
||||||
@Operation(summary = "MES备品件类别-分页列表查询")
|
@Operation(summary = "MES备品件类别-分页列表查询")
|
||||||
@GetMapping(value = "/list")
|
@GetMapping(value = "/list")
|
||||||
public Result<IPage<MesXslSparePartsCategory>> queryPageList(
|
public Result<IPage<MesXslSparePartsCategory>> queryPageList(
|
||||||
@@ -90,6 +94,10 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
|
|||||||
@RequiresPermissions("mes:mes_xsl_spare_parts_category:delete")
|
@RequiresPermissions("mes:mes_xsl_spare_parts_category:delete")
|
||||||
@DeleteMapping(value = "/delete")
|
@DeleteMapping(value = "/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
|
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);
|
mesXslSparePartsCategoryService.removeById(id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
@@ -99,6 +107,10 @@ public class MesXslSparePartsCategoryController extends JeecgController<MesXslSp
|
|||||||
@RequiresPermissions("mes:mes_xsl_spare_parts_category:deleteBatch")
|
@RequiresPermissions("mes:mes_xsl_spare_parts_category:deleteBatch")
|
||||||
@DeleteMapping(value = "/deleteBatch")
|
@DeleteMapping(value = "/deleteBatch")
|
||||||
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
|
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(",")));
|
mesXslSparePartsCategoryService.removeByIds(Arrays.asList(ids.split(",")));
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.jeecg.modules.xslmes.dingtalk.service;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
import org.jeecg.modules.print.vo.PrintBizFieldItemVO;
|
import org.jeecg.modules.print.vo.PrintBizFieldItemVO;
|
||||||
import org.jeecg.modules.system.service.ISysDictService;
|
import org.jeecg.modules.system.service.ISysDictService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -79,7 +80,7 @@ public class DingTplBindFieldValueResolver {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (cur instanceof Map) {
|
if (cur instanceof Map) {
|
||||||
cur = ((Map<String, Object>) cur).get(p);
|
cur = getMapValue((Map<String, Object>) cur, p);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -87,6 +88,32 @@ public class DingTplBindFieldValueResolver {
|
|||||||
return cur;
|
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")
|
@SuppressWarnings("unchecked")
|
||||||
private String getDictTextFromRow(Object rowData, String bizField) {
|
private String getDictTextFromRow(Object rowData, String bizField) {
|
||||||
if (!(rowData instanceof Map) || StringUtils.isBlank(bizField)) {
|
if (!(rowData instanceof Map) || StringUtils.isBlank(bizField)) {
|
||||||
@@ -95,13 +122,13 @@ public class DingTplBindFieldValueResolver {
|
|||||||
Map<String, Object> map = (Map<String, Object>) rowData;
|
Map<String, Object> map = (Map<String, Object>) rowData;
|
||||||
String[] parts = bizField.split("\\.");
|
String[] parts = bizField.split("\\.");
|
||||||
if (parts.length == 1) {
|
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;
|
return v != null ? String.valueOf(v) : null;
|
||||||
}
|
}
|
||||||
String parentPath = String.join(".", java.util.Arrays.copyOf(parts, parts.length - 1));
|
String parentPath = String.join(".", java.util.Arrays.copyOf(parts, parts.length - 1));
|
||||||
Object parent = getNestedValue(rowData, parentPath);
|
Object parent = getNestedValue(rowData, parentPath);
|
||||||
if (parent instanceof Map) {
|
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 v != null ? String.valueOf(v) : null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -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 "审批中";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,4 +13,7 @@ public interface IMesXslDingTplBindService extends IService<MesXslDingTplBind> {
|
|||||||
|
|
||||||
/** 按业务编码查询绑定记录(未删除的第一条) */
|
/** 按业务编码查询绑定记录(未删除的第一条) */
|
||||||
MesXslDingTplBind getByBizCode(String bizCode);
|
MesXslDingTplBind getByBizCode(String bizCode);
|
||||||
|
|
||||||
|
/** 按前端路由解析启用的钉钉模板绑定(模板停用则返回 null) */
|
||||||
|
MesXslDingTplBind resolveActiveByRoutePath(String routePath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,18 @@ package org.jeecg.modules.xslmes.dingtalk.service.impl;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
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.entity.MesXslDingTplBind;
|
||||||
import org.jeecg.modules.xslmes.dingtalk.mapper.MesXslDingTplBindMapper;
|
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.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 org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 钉钉审批模板绑定 ServiceImpl
|
* 钉钉审批模板绑定 ServiceImpl
|
||||||
*
|
*
|
||||||
@@ -17,8 +24,43 @@ import org.springframework.stereotype.Service;
|
|||||||
public class MesXslDingTplBindServiceImpl extends ServiceImpl<MesXslDingTplBindMapper, MesXslDingTplBind>
|
public class MesXslDingTplBindServiceImpl extends ServiceImpl<MesXslDingTplBindMapper, MesXslDingTplBind>
|
||||||
implements IMesXslDingTplBindService {
|
implements IMesXslDingTplBindService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMesXslDingProcessTplService tplService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MesXslDingTplBind getByBizCode(String bizCode) {
|
public MesXslDingTplBind getByBizCode(String bizCode) {
|
||||||
return getOne(new QueryWrapper<MesXslDingTplBind>().eq("biz_code", bizCode).last("LIMIT 1"));
|
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审批通用化】按路由解析启用的钉钉模板绑定-----------
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -38,6 +38,16 @@ public class MesXslMixerAction implements Serializable {
|
|||||||
@Schema(description = "设备名称冗余")
|
@Schema(description = "设备名称冗余")
|
||||||
private String equipmentName;
|
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)
|
@Excel(name = "动作名称", width = 20)
|
||||||
@Schema(description = "动作名称")
|
@Schema(description = "动作名称")
|
||||||
private String actionName;
|
private String actionName;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -89,6 +89,20 @@ public class MesXslMixingSpec implements Serializable {
|
|||||||
@Schema(description = "自动小料打印设定")
|
@Schema(description = "自动小料打印设定")
|
||||||
private String autoSmallPrintSetting;
|
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 = "设定车数")
|
@Schema(description = "设定车数")
|
||||||
private Integer setTrainCount;
|
private Integer setTrainCount;
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
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 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 = "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;
|
||||||
|
}
|
||||||
@@ -78,6 +78,7 @@ public class MesXslRubberQuickTestRecord implements Serializable {
|
|||||||
private Date inspectTime;
|
private Date inspectTime;
|
||||||
|
|
||||||
@Schema(description = "检验人用户ID")
|
@Schema(description = "检验人用户ID")
|
||||||
|
@Dict(dictTable = "sys_user", dicText = "realname", dicCode = "id")
|
||||||
private String inspectorUserId;
|
private String inspectorUserId;
|
||||||
|
|
||||||
private String inspectorUsername;
|
private String inspectorUsername;
|
||||||
@@ -129,4 +130,8 @@ public class MesXslRubberQuickTestRecord implements Serializable {
|
|||||||
|
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private List<MesXslRubberQuickTestRecordLine> lineList;
|
private List<MesXslRubberQuickTestRecordLine> lineList;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
@Schema(description = "原始数据明细(试验结果全部检测值)")
|
||||||
|
private List<MesXslRubberQuickTestRecordRawLine> rawLineList;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -106,4 +106,12 @@ public class MesXslRubberQuickTestStd implements Serializable {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
@Schema(description = "标准明细")
|
@Schema(description = "标准明细")
|
||||||
private List<MesXslRubberQuickTestStdLine> lineList;
|
private List<MesXslRubberQuickTestStdLine> lineList;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
@Schema(description = "实验类型ID(来自实验方法,桌面端展示)")
|
||||||
|
private String quickTestTypeId;
|
||||||
|
|
||||||
|
@TableField(exist = false)
|
||||||
|
@Schema(description = "实验类型名称(来自实验方法,桌面端展示)")
|
||||||
|
private String quickTestTypeName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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> {}
|
||||||
@@ -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> {}
|
||||||
@@ -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> {}
|
||||||
@@ -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> {}
|
||||||
@@ -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> {}
|
||||||
@@ -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上辅机】启动时加载中间库可视化配置-----------
|
||||||
|
}
|
||||||
@@ -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层拦截中间库读写请求-----------
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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上辅机】读取开关拦截全部中间表查询-----------
|
||||||
|
}
|
||||||
@@ -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中间库可视化配置-----------
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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> {
|
||||||
|
}
|
||||||
@@ -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> {
|
||||||
|
}
|
||||||
@@ -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> {
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES上辅机 SQL Server 中间库配置 Service
|
||||||
|
*/
|
||||||
|
public interface IMesXslMcsDbConfigService extends IService<MesXslMcsDbConfig> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前租户配置(无则返回 null)
|
||||||
|
*/
|
||||||
|
MesXslMcsDbConfig getCurrentConfig(Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存或更新配置并刷新动态数据源
|
||||||
|
*/
|
||||||
|
Result<String> saveOrUpdateConfig(MesXslMcsDbConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试数据库连接
|
||||||
|
*/
|
||||||
|
Result<String> testConnection(Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除配置并移除动态数据源
|
||||||
|
*/
|
||||||
|
Result<String> deleteConfig(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动时加载中间库配置(不限定租户,取最近更新的一条)
|
||||||
|
*/
|
||||||
|
MesXslMcsDbConfig loadStartupConfig();
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES上辅机 中间表采集配置 Service(配置驱动:表/字段绑定 + 采集操作)
|
||||||
|
*
|
||||||
|
* @author GHT
|
||||||
|
* @date 2026-06-17 for:【MES上辅机】采集配置-表与字段绑定
|
||||||
|
*/
|
||||||
|
public interface IMesXslMcsSyncConfigService extends IService<MesXslMcsSyncConfig> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取配置详情(含字段映射明细 fieldList)
|
||||||
|
*/
|
||||||
|
MesXslMcsSyncConfig getDetail(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按业务类型获取最近配置(密炼动作页用,bizType=MIX_ACT)
|
||||||
|
*/
|
||||||
|
MesXslMcsSyncConfig getByBizType(String bizType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存配置(头 + 字段映射明细,主子整存)
|
||||||
|
*/
|
||||||
|
Result<String> saveConfig(MesXslMcsSyncConfig config);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除配置及其字段映射,并停止采集
|
||||||
|
*/
|
||||||
|
Result<String> deleteConfig(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 采集操作:维护是否采集、采集间隔、采集模式(全量/时间/增量)及其参数。
|
||||||
|
* status='1' 启动并按间隔重排,'0' 停止。
|
||||||
|
*/
|
||||||
|
Result<String> saveCollect(MesXslMcsSyncConfig body);
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesMixAlarmService;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMesXslEquipAlarmRecordService;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.util.McsQueryHelper;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.util.MesXslMcsMixAlarmConvertUtil;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipAlarmRecordVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备报警记录
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MesXslEquipAlarmRecordServiceImpl implements IMesXslEquipAlarmRecordService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMcsToMesMixAlarmService mcsToMesMixAlarmService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslMcsMixAlarmReadMarker mesXslMcsMixAlarmReadMarker;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPage<MesXslEquipAlarmRecordVO> queryPage(McsToMesMixAlarm query, Map<String, String[]> paramMap, int pageNo, int pageSize) {
|
||||||
|
QueryWrapper<McsToMesMixAlarm> queryWrapper = McsQueryHelper.buildWrapper(query, paramMap);
|
||||||
|
Page<McsToMesMixAlarm> page = new Page<>(pageNo, pageSize);
|
||||||
|
IPage<McsToMesMixAlarm> rawPage = mcsToMesMixAlarmService.page(page, queryWrapper);
|
||||||
|
//update-begin---author:jiangxh ---date:20250604 for:【MES】设备报警记录列表查询后回写 MCS 读取时间与标识-----------
|
||||||
|
mesXslMcsMixAlarmReadMarker.markAsRead(rawPage.getRecords());
|
||||||
|
//update-end---author:jiangxh ---date:20250604 for:【MES】设备报警记录列表查询后回写 MCS 读取时间与标识-----------
|
||||||
|
Page<MesXslEquipAlarmRecordVO> voPage = new Page<>(pageNo, pageSize, rawPage.getTotal());
|
||||||
|
voPage.setRecords(rawPage.getRecords().stream().map(MesXslMcsMixAlarmConvertUtil::toAlarmVo).collect(Collectors.toList()));
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslEquipAlarmRecordVO queryById(String id) {
|
||||||
|
McsToMesMixAlarm row = mcsToMesMixAlarmService.getById(id);
|
||||||
|
if (row == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return MesXslMcsMixAlarmConvertUtil.toAlarmVo(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MesXslEquipAlarmRecordVO> listForExport(McsToMesMixAlarm query, Map<String, String[]> paramMap) {
|
||||||
|
QueryWrapper<McsToMesMixAlarm> queryWrapper = McsQueryHelper.buildWrapper(query, paramMap);
|
||||||
|
return mcsToMesMixAlarmService.list(queryWrapper).stream()
|
||||||
|
.map(MesXslMcsMixAlarmConvertUtil::toAlarmVo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesMixAlarmService;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMesXslEquipDowntimeRecordService;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.util.McsQueryHelper;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.util.MesXslMcsMixAlarmConvertUtil;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipDowntimeRecordVO;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备停机记录
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class MesXslEquipDowntimeRecordServiceImpl implements IMesXslEquipDowntimeRecordService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMcsToMesMixAlarmService mcsToMesMixAlarmService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslMcsMixAlarmReadMarker mesXslMcsMixAlarmReadMarker;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IPage<MesXslEquipDowntimeRecordVO> queryPage(McsToMesMixAlarm query, Map<String, String[]> paramMap, int pageNo, int pageSize) {
|
||||||
|
QueryWrapper<McsToMesMixAlarm> queryWrapper = McsQueryHelper.buildWrapper(query, paramMap);
|
||||||
|
Page<McsToMesMixAlarm> page = new Page<>(pageNo, pageSize);
|
||||||
|
IPage<McsToMesMixAlarm> rawPage = mcsToMesMixAlarmService.page(page, queryWrapper);
|
||||||
|
//update-begin---author:jiangxh ---date:20250604 for:【MES】设备停机记录列表查询后回写 MCS 读取时间与标识-----------
|
||||||
|
mesXslMcsMixAlarmReadMarker.markAsRead(rawPage.getRecords());
|
||||||
|
//update-end---author:jiangxh ---date:20250604 for:【MES】设备停机记录列表查询后回写 MCS 读取时间与标识-----------
|
||||||
|
Page<MesXslEquipDowntimeRecordVO> voPage = new Page<>(pageNo, pageSize, rawPage.getTotal());
|
||||||
|
voPage.setRecords(rawPage.getRecords().stream().map(MesXslMcsMixAlarmConvertUtil::toDowntimeVo).collect(Collectors.toList()));
|
||||||
|
return voPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslEquipDowntimeRecordVO queryById(String id) {
|
||||||
|
McsToMesMixAlarm row = mcsToMesMixAlarmService.getById(id);
|
||||||
|
if (row == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return MesXslMcsMixAlarmConvertUtil.toDowntimeVo(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<MesXslEquipDowntimeRecordVO> listForExport(McsToMesMixAlarm query, Map<String, String[]> paramMap) {
|
||||||
|
QueryWrapper<McsToMesMixAlarm> queryWrapper = McsQueryHelper.buildWrapper(query, paramMap);
|
||||||
|
return mcsToMesMixAlarmService.list(queryWrapper).stream()
|
||||||
|
.map(MesXslMcsMixAlarmConvertUtil::toDowntimeVo)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsDbConfig;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.MesXslMcsDbConfigMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMesXslMcsDbConfigService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronization;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES上辅机 SQL Server 中间库配置 Service 实现
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MesXslMcsDbConfigServiceImpl extends ServiceImpl<MesXslMcsDbConfigMapper, MesXslMcsDbConfig>
|
||||||
|
implements IMesXslMcsDbConfigService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private McsDataSourceManager mcsDataSourceManager;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslMcsDbConfig getCurrentConfig(Integer tenantId) {
|
||||||
|
int tid = tenantId != null ? tenantId : 0;
|
||||||
|
LambdaQueryWrapper<MesXslMcsDbConfig> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.eq(MesXslMcsDbConfig::getTenantId, tid);
|
||||||
|
qw.orderByDesc(MesXslMcsDbConfig::getUpdateTime);
|
||||||
|
qw.last("LIMIT 1");
|
||||||
|
MesXslMcsDbConfig config = getOne(qw, false);
|
||||||
|
if (config != null) {
|
||||||
|
config.setDbPassword(null);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:GHT ---date:20260616 for:【MES上辅机】启动时加载中间库配置(不限定租户)-----------
|
||||||
|
@Override
|
||||||
|
public MesXslMcsDbConfig loadStartupConfig() {
|
||||||
|
LambdaQueryWrapper<MesXslMcsDbConfig> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.orderByDesc(MesXslMcsDbConfig::getUpdateTime);
|
||||||
|
qw.last("LIMIT 1");
|
||||||
|
return getOne(qw, false);
|
||||||
|
}
|
||||||
|
//update-end---author:GHT ---date:20260616 for:【MES上辅机】启动时加载中间库配置(不限定租户)-----------
|
||||||
|
|
||||||
|
//update-begin---author:GHT ---date:20260616 for:【MES上辅机】SQL Server中间库可视化配置-----------
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Result<String> saveOrUpdateConfig(MesXslMcsDbConfig config) {
|
||||||
|
if (config == null) {
|
||||||
|
return Result.error("配置不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(config.getServerHost())) {
|
||||||
|
return Result.error("服务器地址不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(config.getDbUsername())) {
|
||||||
|
return Result.error("用户名不能为空");
|
||||||
|
}
|
||||||
|
if (config.getTenantId() == null) {
|
||||||
|
config.setTenantId(0);
|
||||||
|
}
|
||||||
|
if (config.getServerPort() == null) {
|
||||||
|
config.setServerPort(1433);
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(config.getDbName())) {
|
||||||
|
config.setDbName("MES_ShareDB");
|
||||||
|
}
|
||||||
|
if (config.getReadEnabled() == null) {
|
||||||
|
config.setReadEnabled(1);
|
||||||
|
}
|
||||||
|
if (config.getWriteEnabled() == null) {
|
||||||
|
config.setWriteEnabled(1);
|
||||||
|
}
|
||||||
|
if (config.getStatus() == null) {
|
||||||
|
config.setStatus(0);
|
||||||
|
}
|
||||||
|
if (config.getLoginTimeout() == null) {
|
||||||
|
config.setLoginTimeout(120);
|
||||||
|
}
|
||||||
|
if (config.getConnectTimeout() == null) {
|
||||||
|
config.setConnectTimeout(120000);
|
||||||
|
}
|
||||||
|
|
||||||
|
String plainPassword = resolvePlainPassword(config);
|
||||||
|
if (StringUtils.isBlank(plainPassword)) {
|
||||||
|
return Result.error("密码不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||||
|
if (err != null && Integer.valueOf(1).equals(config.getStatus())) {
|
||||||
|
return Result.error("连接测试失败:" + err);
|
||||||
|
}
|
||||||
|
|
||||||
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
String username = user != null ? user.getUsername() : "system";
|
||||||
|
Date now = new Date();
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(config.getId())) {
|
||||||
|
MesXslMcsDbConfig old = getById(config.getId());
|
||||||
|
if (old == null) {
|
||||||
|
return Result.error("配置不存在");
|
||||||
|
}
|
||||||
|
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||||
|
config.setUpdateBy(username);
|
||||||
|
config.setUpdateTime(now);
|
||||||
|
updateById(config);
|
||||||
|
} else {
|
||||||
|
config.setDbPassword(mcsDataSourceManager.encryptPassword(plainPassword));
|
||||||
|
config.setCreateBy(username);
|
||||||
|
config.setCreateTime(now);
|
||||||
|
config.setUpdateBy(username);
|
||||||
|
config.setUpdateTime(now);
|
||||||
|
save(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
MesXslMcsDbConfig applied = getById(config.getId());
|
||||||
|
scheduleApplyAfterCommit(applied);
|
||||||
|
return Result.OK("保存成功,中间库连接已热刷新,无需重启后端");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 事务提交后再刷新数据源,避免库未落盘就切换连接
|
||||||
|
*/
|
||||||
|
private void scheduleApplyAfterCommit(MesXslMcsDbConfig applied) {
|
||||||
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
||||||
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
||||||
|
@Override
|
||||||
|
public void afterCommit() {
|
||||||
|
mcsDataSourceManager.applyConfig(applied);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
mcsDataSourceManager.applyConfig(applied);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<String> testConnection(Integer tenantId) {
|
||||||
|
MesXslMcsDbConfig config = getOneByTenant(tenantId);
|
||||||
|
if (config == null) {
|
||||||
|
return Result.error("尚未配置中间库连接");
|
||||||
|
}
|
||||||
|
String plainPassword = mcsDataSourceManager.decryptPassword(config.getDbPassword());
|
||||||
|
String err = mcsDataSourceManager.testConnection(config, plainPassword);
|
||||||
|
if (err == null) {
|
||||||
|
return Result.OK("连接成功");
|
||||||
|
}
|
||||||
|
return Result.error("连接失败:" + err);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Result<String> deleteConfig(String id) {
|
||||||
|
MesXslMcsDbConfig config = getById(id);
|
||||||
|
if (config == null) {
|
||||||
|
return Result.error("配置不存在");
|
||||||
|
}
|
||||||
|
removeById(id);
|
||||||
|
mcsDataSourceManager.applyConfig(null);
|
||||||
|
return Result.OK("已删除配置,中间库连接已断开(无需重启后端)");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MesXslMcsDbConfig getOneByTenant(Integer tenantId) {
|
||||||
|
int tid = tenantId != null ? tenantId : 0;
|
||||||
|
LambdaQueryWrapper<MesXslMcsDbConfig> qw = new LambdaQueryWrapper<>();
|
||||||
|
qw.eq(MesXslMcsDbConfig::getTenantId, tid);
|
||||||
|
qw.orderByDesc(MesXslMcsDbConfig::getUpdateTime);
|
||||||
|
qw.last("LIMIT 1");
|
||||||
|
return getOne(qw, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolvePlainPassword(MesXslMcsDbConfig config) {
|
||||||
|
if (StringUtils.isNotBlank(config.getDbPassword())) {
|
||||||
|
return config.getDbPassword();
|
||||||
|
}
|
||||||
|
if (StringUtils.isNotBlank(config.getId())) {
|
||||||
|
MesXslMcsDbConfig old = getById(config.getId());
|
||||||
|
if (old != null) {
|
||||||
|
return mcsDataSourceManager.decryptPassword(old.getDbPassword());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
//update-end---author:GHT ---date:20260616 for:【MES上辅机】SQL Server中间库可视化配置-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.service.IMcsToMesMixAlarmService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 列表查询后将 MCSToMES_MixAlarm 标记为已读(ReadTime、MES_Flag=1)
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class MesXslMcsMixAlarmReadMarker {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMcsToMesMixAlarmService mcsToMesMixAlarmService;
|
||||||
|
|
||||||
|
public void markAsRead(List<McsToMesMixAlarm> records) {
|
||||||
|
if (records == null || records.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Date now = new Date();
|
||||||
|
for (McsToMesMixAlarm row : records) {
|
||||||
|
if (oConvertUtils.isEmpty(row.getGuid())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
McsToMesMixAlarm upd = new McsToMesMixAlarm();
|
||||||
|
upd.setGuid(row.getGuid());
|
||||||
|
upd.setReadTime(now);
|
||||||
|
upd.setMesFlag(1);
|
||||||
|
mcsToMesMixAlarmService.updateById(upd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.vo.LoginUser;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.MesXslMcsSyncConfigMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.MesXslMcsSyncFieldMapper;
|
||||||
|
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.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES上辅机 中间表采集配置 Service 实现
|
||||||
|
*
|
||||||
|
* @author GHT
|
||||||
|
* @date 2026-06-17 for:【MES上辅机】采集配置-表与字段绑定
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class MesXslMcsSyncConfigServiceImpl extends ServiceImpl<MesXslMcsSyncConfigMapper, MesXslMcsSyncConfig>
|
||||||
|
implements IMesXslMcsSyncConfigService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslMcsSyncFieldMapper syncFieldMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private McsSyncScheduler syncScheduler;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslMcsSyncConfig getDetail(String id) {
|
||||||
|
MesXslMcsSyncConfig cfg = getById(id);
|
||||||
|
if (cfg == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
cfg.setFieldList(listFields(id));
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MesXslMcsSyncConfig getByBizType(String bizType) {
|
||||||
|
return getOne(new LambdaQueryWrapper<MesXslMcsSyncConfig>()
|
||||||
|
.eq(MesXslMcsSyncConfig::getBizType, bizType)
|
||||||
|
.eq(MesXslMcsSyncConfig::getDelFlag, 0)
|
||||||
|
.orderByDesc(MesXslMcsSyncConfig::getUpdateTime)
|
||||||
|
.last("LIMIT 1"), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Result<String> saveConfig(MesXslMcsSyncConfig config) {
|
||||||
|
if (config == null) {
|
||||||
|
return Result.error("配置不能为空");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(config.getSourceTable())) {
|
||||||
|
return Result.error("请选择中间库源表");
|
||||||
|
}
|
||||||
|
if (StringUtils.isBlank(config.getTargetTable())) {
|
||||||
|
return Result.error("请选择MES目标表");
|
||||||
|
}
|
||||||
|
List<MesXslMcsSyncField> fields = config.getFieldList() != null ? config.getFieldList() : new ArrayList<>();
|
||||||
|
// 至少一个有效映射
|
||||||
|
boolean hasValid = fields.stream().anyMatch(f -> StringUtils.isNotBlank(f.getSourceField())
|
||||||
|
&& StringUtils.isNotBlank(f.getTargetField()));
|
||||||
|
if (!hasValid) {
|
||||||
|
return Result.error("请至少配置一个字段映射(源字段+接收字段)");
|
||||||
|
}
|
||||||
|
|
||||||
|
String username = currentUsername();
|
||||||
|
Date now = new Date();
|
||||||
|
if (config.getIntervalSeconds() == null || config.getIntervalSeconds() < 1) {
|
||||||
|
config.setIntervalSeconds(1);
|
||||||
|
}
|
||||||
|
if (config.getTenantId() == null) {
|
||||||
|
config.setTenantId(0);
|
||||||
|
}
|
||||||
|
config.setDelFlag(0);
|
||||||
|
config.setUpdateBy(username);
|
||||||
|
config.setUpdateTime(now);
|
||||||
|
|
||||||
|
boolean isUpdate = StringUtils.isNotBlank(config.getId());
|
||||||
|
if (isUpdate) {
|
||||||
|
MesXslMcsSyncConfig old = getById(config.getId());
|
||||||
|
if (old == null) {
|
||||||
|
return Result.error("配置不存在");
|
||||||
|
}
|
||||||
|
// 状态由采集操作维护,保存配置不改变运行状态
|
||||||
|
config.setStatus(old.getStatus());
|
||||||
|
updateById(config);
|
||||||
|
} else {
|
||||||
|
if (StringUtils.isBlank(config.getStatus())) {
|
||||||
|
config.setStatus("0");
|
||||||
|
}
|
||||||
|
config.setCreateBy(username);
|
||||||
|
config.setCreateTime(now);
|
||||||
|
save(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 整存字段映射:先物理删除旧映射再插入
|
||||||
|
syncFieldMapper.delete(new LambdaQueryWrapper<MesXslMcsSyncField>()
|
||||||
|
.eq(MesXslMcsSyncField::getConfigId, config.getId()));
|
||||||
|
int sort = 0;
|
||||||
|
for (MesXslMcsSyncField f : fields) {
|
||||||
|
if (StringUtils.isBlank(f.getSourceField())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
f.setId(null);
|
||||||
|
f.setConfigId(config.getId());
|
||||||
|
f.setSortNo(sort++);
|
||||||
|
f.setTenantId(config.getTenantId());
|
||||||
|
f.setDelFlag(0);
|
||||||
|
f.setCreateBy(username);
|
||||||
|
f.setCreateTime(now);
|
||||||
|
f.setUpdateBy(username);
|
||||||
|
f.setUpdateTime(now);
|
||||||
|
syncFieldMapper.insert(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 运行中则按新配置重排(间隔/映射即时生效)
|
||||||
|
if ("1".equals(config.getStatus())) {
|
||||||
|
syncScheduler.scheduleTask(getById(config.getId()));
|
||||||
|
}
|
||||||
|
return Result.OK(isUpdate ? "保存成功" : "新增成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Result<String> deleteConfig(String id) {
|
||||||
|
MesXslMcsSyncConfig cfg = getById(id);
|
||||||
|
if (cfg == null) {
|
||||||
|
return Result.error("配置不存在");
|
||||||
|
}
|
||||||
|
syncScheduler.cancelTask(id);
|
||||||
|
syncFieldMapper.delete(new LambdaQueryWrapper<MesXslMcsSyncField>()
|
||||||
|
.eq(MesXslMcsSyncField::getConfigId, id));
|
||||||
|
removeById(id);
|
||||||
|
return Result.OK("删除成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Result<String> saveCollect(MesXslMcsSyncConfig body) {
|
||||||
|
if (body == null || StringUtils.isBlank(body.getId())) {
|
||||||
|
return Result.error("缺少配置ID");
|
||||||
|
}
|
||||||
|
MesXslMcsSyncConfig cfg = getById(body.getId());
|
||||||
|
if (cfg == null) {
|
||||||
|
return Result.error("配置不存在");
|
||||||
|
}
|
||||||
|
if (body.getIntervalSeconds() != null) {
|
||||||
|
if (body.getIntervalSeconds() < 1) {
|
||||||
|
return Result.error("采集间隔不能小于1秒");
|
||||||
|
}
|
||||||
|
cfg.setIntervalSeconds(body.getIntervalSeconds());
|
||||||
|
}
|
||||||
|
// 采集模式及参数
|
||||||
|
String mode = StringUtils.isBlank(body.getSyncMode()) ? "FULL" : body.getSyncMode().trim().toUpperCase();
|
||||||
|
cfg.setSyncMode(mode);
|
||||||
|
cfg.setIncrColumn(StringUtils.trimToNull(body.getIncrColumn()));
|
||||||
|
cfg.setTimeWindow(StringUtils.isBlank(body.getTimeWindow()) ? "TODAY" : body.getTimeWindow());
|
||||||
|
if (body.getBatchLimit() != null && body.getBatchLimit() > 0) {
|
||||||
|
cfg.setBatchLimit(body.getBatchLimit());
|
||||||
|
}
|
||||||
|
// INCR(标记回写):采集条件 + 回写值(可视化配置,回写值默认"1")
|
||||||
|
cfg.setFlagCondition(StringUtils.isBlank(body.getFlagCondition()) ? "IS_NULL" : body.getFlagCondition().trim().toUpperCase());
|
||||||
|
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】增量采集条件等于/不等于支持自定义匹配值-----------
|
||||||
|
cfg.setFlagMatchValue(body.getFlagMatchValue());
|
||||||
|
//update-end---author:GHT ---date:20260617 for:【MES上辅机】增量采集条件等于/不等于支持自定义匹配值-----------
|
||||||
|
cfg.setFlagWriteValue(StringUtils.isBlank(body.getFlagWriteValue()) ? "1" : body.getFlagWriteValue());
|
||||||
|
if (("TIME".equals(mode) || "INCR".equals(mode)) && StringUtils.isBlank(cfg.getIncrColumn())) {
|
||||||
|
return Result.error("时间匹配/增量匹配需选择" + ("TIME".equals(mode) ? "时间列" : "标记列"));
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean on = "1".equals(body.getStatus());
|
||||||
|
cfg.setStatus(on ? "1" : "0");
|
||||||
|
cfg.setUpdateBy(currentUsername());
|
||||||
|
cfg.setUpdateTime(new Date());
|
||||||
|
updateById(cfg);
|
||||||
|
if (on) {
|
||||||
|
syncScheduler.scheduleTask(cfg);
|
||||||
|
return Result.OK("已启动采集(" + modeText(mode) + "),间隔 " + cfg.getIntervalSeconds() + " 秒");
|
||||||
|
}
|
||||||
|
syncScheduler.cancelTask(cfg.getId());
|
||||||
|
return Result.OK("已停止采集");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String modeText(String mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case "TIME":
|
||||||
|
return "时间匹配";
|
||||||
|
case "INCR":
|
||||||
|
return "增量匹配";
|
||||||
|
default:
|
||||||
|
return "全量匹配";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<MesXslMcsSyncField> listFields(String configId) {
|
||||||
|
return syncFieldMapper.selectList(new LambdaQueryWrapper<MesXslMcsSyncField>()
|
||||||
|
.eq(MesXslMcsSyncField::getConfigId, configId)
|
||||||
|
.eq(MesXslMcsSyncField::getDelFlag, 0)
|
||||||
|
.orderByAsc(MesXslMcsSyncField::getSortNo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String currentUsername() {
|
||||||
|
try {
|
||||||
|
LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||||
|
return user != null ? user.getUsername() : "system";
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "system";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,524 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.sync;
|
||||||
|
|
||||||
|
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.McsMetaMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通用中间表采集引擎(配置驱动,纯字段拷贝)。
|
||||||
|
* <p>支持三种采集模式,应对中间库不同规模的表:</p>
|
||||||
|
* <ul>
|
||||||
|
* <li><b>FULL 全量匹配</b>:全表读源+全表读目标→按匹配键 Upsert,仅写新增/变化行。适合小状态表、以更新为主。</li>
|
||||||
|
* <li><b>TIME 时间匹配</b>:按时间列只取窗口内数据(当天/最近七天)→按匹配键 Upsert,目标侧按窗口匹配键定向读取。避免全表扫描。</li>
|
||||||
|
* <li><b>INCR 增量匹配(标记位回写)</b>:源表选一「同步标记列」,仅采集该列为空(NULL/'')的行(TOP N 限流),
|
||||||
|
* 按匹配键 Upsert 到 MES 后,回写源表该列为 {@code '1'},下轮不再重复采集。适合带 GUID 主键、无可靠递增列的流水表。</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @author GHT
|
||||||
|
* @date 2026-06-17 for:【MES上辅机】采集配置-表与字段绑定
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class GenericMcsSyncEngine {
|
||||||
|
|
||||||
|
public static final String MODE_FULL = "FULL";
|
||||||
|
public static final String MODE_TIME = "TIME";
|
||||||
|
public static final String MODE_INCR = "INCR";
|
||||||
|
|
||||||
|
/** 合法标识符(表名/列名),防止 SQL 注入 */
|
||||||
|
private static final Pattern IDENT = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||||
|
|
||||||
|
/** 批量写入分批大小 */
|
||||||
|
private static final int BATCH_SIZE = 500;
|
||||||
|
/** IN 查询分块大小 */
|
||||||
|
private static final int IN_CHUNK = 1000;
|
||||||
|
/** INCR 默认每轮行数 */
|
||||||
|
private static final int DEFAULT_BATCH_LIMIT = 2000;
|
||||||
|
/** INCR 标记位回写后的已同步标识值 */
|
||||||
|
private static final String FLAG_SYNCED = "1";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DataSource dataSource;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private McsMetaMapper metaMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager mcsDataSourceManager;
|
||||||
|
|
||||||
|
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】采集模式 全量/时间/增量-----------
|
||||||
|
public String sync(MesXslMcsSyncConfig cfg, List<MesXslMcsSyncField> fields) {
|
||||||
|
String sourceTable = trim(cfg.getSourceTable());
|
||||||
|
String targetTable = trim(cfg.getTargetTable());
|
||||||
|
if (StringUtils.isBlank(sourceTable) || StringUtils.isBlank(targetTable)) {
|
||||||
|
return "未配置源表或目标表,跳过";
|
||||||
|
}
|
||||||
|
validateIdent(sourceTable);
|
||||||
|
validateIdent(targetTable);
|
||||||
|
|
||||||
|
List<MesXslMcsSyncField> maps = fields == null ? List.of() : fields.stream()
|
||||||
|
.filter(f -> StringUtils.isNotBlank(f.getSourceField()) && StringUtils.isNotBlank(f.getTargetField()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (maps.isEmpty()) {
|
||||||
|
return "无有效字段映射,跳过";
|
||||||
|
}
|
||||||
|
for (MesXslMcsSyncField f : maps) {
|
||||||
|
validateIdent(f.getSourceField());
|
||||||
|
validateIdent(f.getTargetField());
|
||||||
|
}
|
||||||
|
|
||||||
|
String mode = StringUtils.isBlank(cfg.getSyncMode()) ? MODE_FULL : cfg.getSyncMode().trim().toUpperCase();
|
||||||
|
JdbcTemplate sourceJt = new JdbcTemplate(getSourceDataSource());
|
||||||
|
JdbcTemplate targetJt = new JdbcTemplate(dataSource);
|
||||||
|
|
||||||
|
// 目标表标准字段探测 + 自动填充列
|
||||||
|
Set<String> targetCols = metaMapper.listTargetColumns(targetTable).stream()
|
||||||
|
.map(m -> String.valueOf(m.get("columnName")).toLowerCase())
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
boolean hasDel = targetCols.contains("del_flag");
|
||||||
|
|
||||||
|
List<MesXslMcsSyncField> keyMaps = maps.stream().filter(f -> "1".equals(f.getMatchKey())).collect(Collectors.toList());
|
||||||
|
Set<String> keyTargetsLower = keyMaps.stream().map(k -> k.getTargetField().toLowerCase()).collect(Collectors.toSet());
|
||||||
|
List<MesXslMcsSyncField> nonKeyMaps = maps.stream()
|
||||||
|
.filter(f -> !keyTargetsLower.contains(f.getTargetField().toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
int tenantId = cfg.getTenantId() != null ? cfg.getTenantId() : 0;
|
||||||
|
Timestamp now = new Timestamp(System.currentTimeMillis());
|
||||||
|
|
||||||
|
AutoCols auto = buildAutoCols(targetCols, maps, tenantId, now);
|
||||||
|
|
||||||
|
// 1. 按模式读源数据
|
||||||
|
LinkedHashSet<String> srcCols = maps.stream().map(MesXslMcsSyncField::getSourceField)
|
||||||
|
.collect(Collectors.toCollection(LinkedHashSet::new));
|
||||||
|
List<Map<String, Object>> rows;
|
||||||
|
|
||||||
|
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||||
|
// INCR(标记回写)模式:仅采集「标记列」为空的行,采完回写"1",下轮不再重复采集
|
||||||
|
String flagCol = null;
|
||||||
|
boolean flagMode = MODE_INCR.equals(mode);
|
||||||
|
|
||||||
|
if (flagMode) {
|
||||||
|
flagCol = requireIncrColumn(cfg);
|
||||||
|
if (keyMaps.isEmpty()) {
|
||||||
|
return "增量(标记)采集需在字段映射中勾选至少一个匹配键作为回写主键(如 GUID)";
|
||||||
|
}
|
||||||
|
if (!mcsDataSourceManager.isWriteEnabled()) {
|
||||||
|
return "增量(标记)采集需开启中间库写入开关以回写同步标记,请在「中间库连接配置」开启写入";
|
||||||
|
}
|
||||||
|
srcCols.add(flagCol);
|
||||||
|
int limit = cfg.getBatchLimit() != null && cfg.getBatchLimit() > 0 ? cfg.getBatchLimit() : DEFAULT_BATCH_LIMIT;
|
||||||
|
String predicate = flagPredicate(flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue());
|
||||||
|
String sql = "SELECT TOP " + limit + " " + colList(srcCols) + " FROM [" + sourceTable + "]"
|
||||||
|
+ " WHERE (" + predicate + ")";
|
||||||
|
rows = sourceJt.queryForList(sql);
|
||||||
|
if (rows.isEmpty()) {
|
||||||
|
return "增量采集:无待采集数据";
|
||||||
|
}
|
||||||
|
} else if (MODE_TIME.equals(mode)) {
|
||||||
|
String incrCol = requireIncrColumn(cfg);
|
||||||
|
Timestamp[] window = timeWindow(cfg.getTimeWindow(), now);
|
||||||
|
StringBuilder sql = new StringBuilder("SELECT ").append(colList(srcCols))
|
||||||
|
.append(" FROM [").append(sourceTable).append("] WHERE [").append(incrCol).append("] >= ?");
|
||||||
|
List<Object> args = new ArrayList<>();
|
||||||
|
args.add(window[0]);
|
||||||
|
if (window[1] != null) {
|
||||||
|
sql.append(" AND [").append(incrCol).append("] < ?");
|
||||||
|
args.add(window[1]);
|
||||||
|
}
|
||||||
|
rows = sourceJt.queryForList(sql.toString(), args.toArray());
|
||||||
|
} else {
|
||||||
|
// FULL
|
||||||
|
rows = sourceJt.queryForList("SELECT " + colList(srcCols) + " FROM [" + sourceTable + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows.isEmpty()) {
|
||||||
|
return ("TIME".equals(mode) ? "时间匹配" : "全量匹配") + ":窗口/源表无数据,未更新";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无匹配键 → 整批追加
|
||||||
|
if (keyMaps.isEmpty()) {
|
||||||
|
int ins = appendInsert(targetJt, targetTable, maps, auto, rows);
|
||||||
|
return String.format("采集完成(无匹配键,追加):新增%d,源%d条", ins, rows.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 加载现有目标数据(FULL 全量;TIME/INCR 仅按本批匹配键定向读取)
|
||||||
|
LinkedHashSet<String> existCols = new LinkedHashSet<>();
|
||||||
|
keyMaps.forEach(k -> existCols.add(k.getTargetField()));
|
||||||
|
maps.forEach(m -> existCols.add(m.getTargetField()));
|
||||||
|
Map<String, Map<String, Object>> existingByKey = (MODE_TIME.equals(mode) || flagMode)
|
||||||
|
? loadExistingByKeys(targetJt, targetTable, existCols, keyMaps, hasDel, rows)
|
||||||
|
: loadExistingAll(targetJt, targetTable, existCols, keyMaps, hasDel);
|
||||||
|
|
||||||
|
// 3. 比对 → 批量 Upsert
|
||||||
|
List<String> updateSetCols = nonKeyMaps.stream().map(MesXslMcsSyncField::getTargetField).collect(Collectors.toList());
|
||||||
|
boolean updTime = targetCols.contains("update_time") && !mappedContains(maps, "update_time");
|
||||||
|
boolean updBy = targetCols.contains("update_by") && !mappedContains(maps, "update_by");
|
||||||
|
String updateSql = buildUpdateSql(targetTable, updateSetCols, keyMaps, updTime, updBy, hasDel);
|
||||||
|
String insertSql = buildInsertSql(targetTable, maps, auto);
|
||||||
|
|
||||||
|
List<Object[]> insertArgs = new ArrayList<>();
|
||||||
|
List<Object[]> updateArgs = new ArrayList<>();
|
||||||
|
Set<String> handled = new HashSet<>();
|
||||||
|
int unchanged = 0;
|
||||||
|
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Map<String, Object> rci = ci(row);
|
||||||
|
String key = buildKeyFromSource(keyMaps, rci);
|
||||||
|
if (!handled.add(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<String, Object> existing = existingByKey.get(key);
|
||||||
|
if (existing == null) {
|
||||||
|
insertArgs.add(buildInsertArgs(maps, rci, auto));
|
||||||
|
} else if (updateSetCols.isEmpty()) {
|
||||||
|
unchanged++;
|
||||||
|
} else if (isChanged(nonKeyMaps, rci, existing)) {
|
||||||
|
updateArgs.add(buildUpdateArgs(nonKeyMaps, keyMaps, rci, updTime, updBy, now));
|
||||||
|
} else {
|
||||||
|
unchanged++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int ins = batch(targetJt, insertSql, insertArgs);
|
||||||
|
int upd = updateSetCols.isEmpty() ? 0 : batch(targetJt, updateSql, updateArgs);
|
||||||
|
|
||||||
|
// INCR(标记回写):对本批所有源行回写标记值,下轮不再采集
|
||||||
|
if (flagMode) {
|
||||||
|
String writeValue = StringUtils.isBlank(cfg.getFlagWriteValue()) ? FLAG_SYNCED : cfg.getFlagWriteValue();
|
||||||
|
int marked = writeBackFlag(sourceJt, sourceTable, flagCol, cfg.getFlagCondition(), cfg.getFlagMatchValue(), writeValue, keyMaps, rows);
|
||||||
|
return String.format("增量采集:新增%d,更新%d,未变%d,回写标记%d,源%d条",
|
||||||
|
ins, upd, unchanged, marked, rows.size());
|
||||||
|
}
|
||||||
|
return String.format("%s:新增%d,更新%d,未变%d,源%d条",
|
||||||
|
"TIME".equals(mode) ? "时间匹配" : "全量匹配", ins, upd, unchanged, rows.size());
|
||||||
|
//update-end---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||||
|
}
|
||||||
|
|
||||||
|
//update-begin---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||||
|
/**
|
||||||
|
* INCR 标记采集条件:根据配置构造源表标记列的判定谓词(SELECT 取数 + 回写守卫共用)。
|
||||||
|
* <ul>
|
||||||
|
* <li>{@code IS_NULL} 为空:{@code [col] IS NULL}</li>
|
||||||
|
* <li>{@code EQ_EMPTY} 等于:{@code [col] = '<匹配值>'}(匹配值留空时退化为等于空串)</li>
|
||||||
|
* <li>{@code NE_EMPTY} 不等于:{@code [col] <> '<匹配值>'}(匹配值留空时退化为不等于空串)</li>
|
||||||
|
* </ul>
|
||||||
|
* @param matchValue EQ_EMPTY/NE_EMPTY 的比较值,由用户填写,留空表示空字符串
|
||||||
|
*/
|
||||||
|
private String flagPredicate(String flagCol, String condition, String matchValue) {
|
||||||
|
String c = StringUtils.isBlank(condition) ? "IS_NULL" : condition.trim().toUpperCase();
|
||||||
|
switch (c) {
|
||||||
|
case "EQ_EMPTY":
|
||||||
|
return "[" + flagCol + "] = '" + sqlLiteral(matchValue) + "'";
|
||||||
|
case "NE_EMPTY":
|
||||||
|
return "[" + flagCol + "] <> '" + sqlLiteral(matchValue) + "'";
|
||||||
|
case "IS_NULL":
|
||||||
|
default:
|
||||||
|
return "[" + flagCol + "] IS NULL";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 将用户填写的匹配值转义为 SQL 字符串字面量内容(单引号翻倍),防止注入。 */
|
||||||
|
private String sqlLiteral(String value) {
|
||||||
|
return value == null ? "" : value.replace("'", "''");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* INCR 标记回写:把本批读到的源行该标记列回写为配置的回写值。
|
||||||
|
* <p>仅按匹配键精确定位本批读到的行(而非整列条件批量更新),
|
||||||
|
* 避免误标在本轮 SELECT 之后才进入中间库、尚未采集的新数据;
|
||||||
|
* 并以采集条件谓词做守卫,避开本轮已被其他进程改动的行。</p>
|
||||||
|
*/
|
||||||
|
private int writeBackFlag(JdbcTemplate sourceJt, String sourceTable, String flagCol, String condition,
|
||||||
|
String matchValue, String writeValue, List<MesXslMcsSyncField> keyMaps, List<Map<String, Object>> rows) {
|
||||||
|
validateIdent(flagCol);
|
||||||
|
StringBuilder sql = new StringBuilder("UPDATE [").append(sourceTable).append("] SET [")
|
||||||
|
.append(flagCol).append("] = ? WHERE ");
|
||||||
|
sql.append(keyMaps.stream().map(k -> "[" + k.getSourceField() + "] = ?").collect(Collectors.joining(" AND ")));
|
||||||
|
sql.append(" AND (").append(flagPredicate(flagCol, condition, matchValue)).append(")");
|
||||||
|
List<Object[]> argsList = new ArrayList<>();
|
||||||
|
Set<String> handled = new HashSet<>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Map<String, Object> rci = ci(row);
|
||||||
|
String key = buildKeyFromSource(keyMaps, rci);
|
||||||
|
if (!handled.add(key)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
List<Object> args = new ArrayList<>(keyMaps.size() + 1);
|
||||||
|
args.add(writeValue);
|
||||||
|
for (MesXslMcsSyncField k : keyMaps) {
|
||||||
|
args.add(rci.get(k.getSourceField()));
|
||||||
|
}
|
||||||
|
argsList.add(args.toArray());
|
||||||
|
}
|
||||||
|
return batch(sourceJt, sql.toString(), argsList);
|
||||||
|
}
|
||||||
|
//update-end---author:GHT ---date:20260617 for:【MES上辅机】增量匹配改为标记位回写-----------
|
||||||
|
|
||||||
|
// ---------------- 现有数据加载 ----------------
|
||||||
|
|
||||||
|
private Map<String, Map<String, Object>> loadExistingAll(JdbcTemplate jt, String table, LinkedHashSet<String> existCols,
|
||||||
|
List<MesXslMcsSyncField> keyMaps, boolean hasDel) {
|
||||||
|
String sql = "SELECT " + colListBt(existCols) + " FROM `" + table + "`" + (hasDel ? " WHERE `del_flag` = 0" : "");
|
||||||
|
Map<String, Map<String, Object>> map = new HashMap<>();
|
||||||
|
for (Map<String, Object> er : jt.queryForList(sql)) {
|
||||||
|
Map<String, Object> eci = ci(er);
|
||||||
|
map.put(buildKeyFromTarget(keyMaps, eci), eci);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Map<String, Object>> loadExistingByKeys(JdbcTemplate jt, String table, LinkedHashSet<String> existCols,
|
||||||
|
List<MesXslMcsSyncField> keyMaps, boolean hasDel,
|
||||||
|
List<Map<String, Object>> rows) {
|
||||||
|
Map<String, Map<String, Object>> map = new HashMap<>();
|
||||||
|
MesXslMcsSyncField firstKey = keyMaps.get(0);
|
||||||
|
// 收集窗口内首匹配键去重值
|
||||||
|
LinkedHashSet<Object> values = new LinkedHashSet<>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
Object v = ci(row).get(firstKey.getSourceField());
|
||||||
|
if (v != null) {
|
||||||
|
values.add(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (values.isEmpty()) {
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
List<Object> valueList = new ArrayList<>(values);
|
||||||
|
for (int i = 0; i < valueList.size(); i += IN_CHUNK) {
|
||||||
|
List<Object> part = valueList.subList(i, Math.min(i + IN_CHUNK, valueList.size()));
|
||||||
|
String ph = part.stream().map(x -> "?").collect(Collectors.joining(","));
|
||||||
|
String sql = "SELECT " + colListBt(existCols) + " FROM `" + table + "` WHERE `"
|
||||||
|
+ firstKey.getTargetField() + "` IN (" + ph + ")" + (hasDel ? " AND `del_flag` = 0" : "");
|
||||||
|
for (Map<String, Object> er : jt.queryForList(sql, part.toArray())) {
|
||||||
|
Map<String, Object> eci = ci(er);
|
||||||
|
map.put(buildKeyFromTarget(keyMaps, eci), eci);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- 追加写入 ----------------
|
||||||
|
|
||||||
|
private int appendInsert(JdbcTemplate jt, String table, List<MesXslMcsSyncField> maps, AutoCols auto,
|
||||||
|
List<Map<String, Object>> rows) {
|
||||||
|
List<Object[]> insertArgs = new ArrayList<>();
|
||||||
|
for (Map<String, Object> row : rows) {
|
||||||
|
insertArgs.add(buildInsertArgs(maps, ci(row), auto));
|
||||||
|
}
|
||||||
|
return batch(jt, buildInsertSql(table, maps, auto), insertArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- SQL 构建 ----------------
|
||||||
|
|
||||||
|
private String buildInsertSql(String table, List<MesXslMcsSyncField> maps, AutoCols auto) {
|
||||||
|
List<String> cols = new ArrayList<>();
|
||||||
|
maps.forEach(m -> cols.add(m.getTargetField()));
|
||||||
|
if (auto.id) {
|
||||||
|
cols.add("id");
|
||||||
|
}
|
||||||
|
cols.addAll(auto.cols);
|
||||||
|
String colSql = cols.stream().map(c -> "`" + c + "`").collect(Collectors.joining(","));
|
||||||
|
String ph = cols.stream().map(c -> "?").collect(Collectors.joining(","));
|
||||||
|
return "INSERT INTO `" + table + "` (" + colSql + ") VALUES (" + ph + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] buildInsertArgs(List<MesXslMcsSyncField> maps, Map<String, Object> ci, AutoCols auto) {
|
||||||
|
List<Object> args = new ArrayList<>(maps.size() + auto.vals.size() + 1);
|
||||||
|
for (MesXslMcsSyncField m : maps) {
|
||||||
|
args.add(ci.get(m.getSourceField()));
|
||||||
|
}
|
||||||
|
if (auto.id) {
|
||||||
|
args.add(IdWorker.getIdStr());
|
||||||
|
}
|
||||||
|
args.addAll(auto.vals);
|
||||||
|
return args.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildUpdateSql(String table, List<String> setCols, List<MesXslMcsSyncField> keyMaps,
|
||||||
|
boolean updTime, boolean updBy, boolean hasDel) {
|
||||||
|
if (setCols.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder sql = new StringBuilder("UPDATE `").append(table).append("` SET ");
|
||||||
|
sql.append(setCols.stream().map(c -> "`" + c + "` = ?").collect(Collectors.joining(",")));
|
||||||
|
if (updTime) {
|
||||||
|
sql.append(", `update_time` = ?");
|
||||||
|
}
|
||||||
|
if (updBy) {
|
||||||
|
sql.append(", `update_by` = ?");
|
||||||
|
}
|
||||||
|
sql.append(" WHERE ");
|
||||||
|
sql.append(keyMaps.stream().map(k -> "`" + k.getTargetField() + "` = ?").collect(Collectors.joining(" AND ")));
|
||||||
|
if (hasDel) {
|
||||||
|
sql.append(" AND `del_flag` = 0");
|
||||||
|
}
|
||||||
|
return sql.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object[] buildUpdateArgs(List<MesXslMcsSyncField> nonKeyMaps, List<MesXslMcsSyncField> keyMaps,
|
||||||
|
Map<String, Object> ci, boolean updTime, boolean updBy, Timestamp now) {
|
||||||
|
List<Object> args = new ArrayList<>();
|
||||||
|
for (MesXslMcsSyncField m : nonKeyMaps) {
|
||||||
|
args.add(ci.get(m.getSourceField()));
|
||||||
|
}
|
||||||
|
if (updTime) {
|
||||||
|
args.add(now);
|
||||||
|
}
|
||||||
|
if (updBy) {
|
||||||
|
args.add("mcs-sync");
|
||||||
|
}
|
||||||
|
for (MesXslMcsSyncField k : keyMaps) {
|
||||||
|
args.add(ci.get(k.getSourceField()));
|
||||||
|
}
|
||||||
|
return args.toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------- 工具 ----------------
|
||||||
|
|
||||||
|
/** 自动填充列汇总(id 单独标记,因每行不同) */
|
||||||
|
private static class AutoCols {
|
||||||
|
boolean id;
|
||||||
|
final List<String> cols = new ArrayList<>();
|
||||||
|
final List<Object> vals = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
private AutoCols buildAutoCols(Set<String> targetCols, List<MesXslMcsSyncField> maps, int tenantId, Timestamp now) {
|
||||||
|
AutoCols a = new AutoCols();
|
||||||
|
a.id = targetCols.contains("id") && !mappedContains(maps, "id");
|
||||||
|
addAuto(a, targetCols, maps, "create_time", now);
|
||||||
|
addAuto(a, targetCols, maps, "update_time", now);
|
||||||
|
addAuto(a, targetCols, maps, "create_by", "mcs-sync");
|
||||||
|
addAuto(a, targetCols, maps, "update_by", "mcs-sync");
|
||||||
|
addAuto(a, targetCols, maps, "tenant_id", tenantId);
|
||||||
|
addAuto(a, targetCols, maps, "del_flag", 0);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addAuto(AutoCols a, Set<String> targetCols, List<MesXslMcsSyncField> maps, String col, Object val) {
|
||||||
|
if (targetCols.contains(col) && !mappedContains(maps, col)) {
|
||||||
|
a.cols.add(col);
|
||||||
|
a.vals.add(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 返回 [start, end],end 可为 null */
|
||||||
|
private Timestamp[] timeWindow(String window, Timestamp now) {
|
||||||
|
String w = StringUtils.isBlank(window) ? "TODAY" : window.trim().toUpperCase();
|
||||||
|
if ("LAST7".equals(w)) {
|
||||||
|
return new Timestamp[]{Timestamp.valueOf(LocalDateTime.now().minusDays(7)), null};
|
||||||
|
}
|
||||||
|
// 默认当天
|
||||||
|
Timestamp start = Timestamp.valueOf(LocalDate.now().atStartOfDay());
|
||||||
|
Timestamp end = Timestamp.valueOf(LocalDate.now().plusDays(1).atStartOfDay());
|
||||||
|
return new Timestamp[]{start, end};
|
||||||
|
}
|
||||||
|
|
||||||
|
private String requireIncrColumn(MesXslMcsSyncConfig cfg) {
|
||||||
|
String col = trim(cfg.getIncrColumn());
|
||||||
|
if (StringUtils.isBlank(col)) {
|
||||||
|
throw new IllegalArgumentException("当前采集模式需指定标记列/时间列,请在采集操作中配置");
|
||||||
|
}
|
||||||
|
validateIdent(col);
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int batch(JdbcTemplate jt, String sql, List<Object[]> argsList) {
|
||||||
|
if (sql == null || argsList.isEmpty()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int total = 0;
|
||||||
|
for (int i = 0; i < argsList.size(); i += BATCH_SIZE) {
|
||||||
|
List<Object[]> part = argsList.subList(i, Math.min(i + BATCH_SIZE, argsList.size()));
|
||||||
|
jt.batchUpdate(sql, part);
|
||||||
|
total += part.size();
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isChanged(List<MesXslMcsSyncField> nonKeyMaps, Map<String, Object> ci, Map<String, Object> existing) {
|
||||||
|
for (MesXslMcsSyncField m : nonKeyMaps) {
|
||||||
|
if (!normVal(ci.get(m.getSourceField())).equals(normVal(existing.get(m.getTargetField())))) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildKeyFromSource(List<MesXslMcsSyncField> keyMaps, Map<String, Object> ci) {
|
||||||
|
return keyMaps.stream().map(k -> normKey(ci.get(k.getSourceField()))).collect(Collectors.joining("||"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String buildKeyFromTarget(List<MesXslMcsSyncField> keyMaps, Map<String, Object> eci) {
|
||||||
|
return keyMaps.stream().map(k -> normKey(eci.get(k.getTargetField()))).collect(Collectors.joining("||"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> ci(Map<String, Object> row) {
|
||||||
|
Map<String, Object> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
|
||||||
|
m.putAll(row);
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String colList(LinkedHashSet<String> cols) {
|
||||||
|
return cols.stream().map(c -> "[" + c + "]").collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String colListBt(LinkedHashSet<String> cols) {
|
||||||
|
return cols.stream().map(c -> "`" + c + "`").collect(Collectors.joining(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normKey(Object v) {
|
||||||
|
return v == null ? "" : String.valueOf(v).trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normVal(Object v) {
|
||||||
|
return v == null ? " " : String.valueOf(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean mappedContains(List<MesXslMcsSyncField> maps, String targetCol) {
|
||||||
|
return maps.stream().anyMatch(m -> m.getTargetField() != null && m.getTargetField().equalsIgnoreCase(targetCol));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DataSource getSourceDataSource() {
|
||||||
|
DynamicRoutingDataSource routing = (DynamicRoutingDataSource) dataSource;
|
||||||
|
DataSource src = routing.getDataSources().get(McsDataSourceManager.DS_KEY);
|
||||||
|
if (src == null) {
|
||||||
|
throw new IllegalStateException("中间库数据源 " + McsDataSourceManager.DS_KEY + " 未注册");
|
||||||
|
}
|
||||||
|
return src;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateIdent(String name) {
|
||||||
|
if (name == null || !IDENT.matcher(name).matches()) {
|
||||||
|
throw new IllegalArgumentException("非法的表名或字段名: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String trim(String s) {
|
||||||
|
return s == null ? null : s.trim();
|
||||||
|
}
|
||||||
|
//update-end---author:GHT ---date:20260617 for:【MES上辅机】采集模式 全量/时间/增量-----------
|
||||||
|
}
|
||||||
@@ -0,0 +1,162 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.sync;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.datasource.McsDataSourceManager;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncConfig;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.MesXslMcsSyncField;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.MesXslMcsSyncConfigMapper;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.mapper.MesXslMcsSyncFieldMapper;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.context.event.ApplicationReadyEvent;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ScheduledFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 中间表采集调度器(通用,配置驱动)。
|
||||||
|
* <p>基于 {@link ThreadPoolTaskScheduler} 为每个运行中的采集配置维护一个可重排的定时任务,
|
||||||
|
* 支持秒级间隔、运行时改间隔、启动/停止。每次触发调用 {@link GenericMcsSyncEngine} 执行采集。</p>
|
||||||
|
*
|
||||||
|
* @author GHT
|
||||||
|
* @date 2026-06-17 for:【MES上辅机】采集配置-表与字段绑定
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class McsSyncScheduler {
|
||||||
|
|
||||||
|
private static final String LOG_TAG = "[MCS采集]";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslMcsSyncConfigMapper syncConfigMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MesXslMcsSyncFieldMapper syncFieldMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private McsDataSourceManager mcsDataSourceManager;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private GenericMcsSyncEngine syncEngine;
|
||||||
|
|
||||||
|
/** 运行中的定时任务,configId -> future */
|
||||||
|
private final Map<String, ScheduledFuture<?>> runningTasks = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private ThreadPoolTaskScheduler taskScheduler;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
taskScheduler = new ThreadPoolTaskScheduler();
|
||||||
|
taskScheduler.setPoolSize(4);
|
||||||
|
taskScheduler.setThreadNamePrefix("mcs-sync-");
|
||||||
|
taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
|
||||||
|
taskScheduler.setAwaitTerminationSeconds(10);
|
||||||
|
taskScheduler.initialize();
|
||||||
|
log.info("{} 采集调度器初始化完成", LOG_TAG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
runningTasks.values().forEach(f -> f.cancel(false));
|
||||||
|
runningTasks.clear();
|
||||||
|
if (taskScheduler != null) {
|
||||||
|
taskScheduler.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用启动后,加载所有 status=1 的采集配置并启动定时任务
|
||||||
|
*/
|
||||||
|
@EventListener(ApplicationReadyEvent.class)
|
||||||
|
public void loadOnStartup() {
|
||||||
|
try {
|
||||||
|
List<MesXslMcsSyncConfig> configs = syncConfigMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMcsSyncConfig>()
|
||||||
|
.eq(MesXslMcsSyncConfig::getDelFlag, 0)
|
||||||
|
.eq(MesXslMcsSyncConfig::getStatus, "1"));
|
||||||
|
configs.forEach(this::scheduleTask);
|
||||||
|
log.info("{} 启动加载采集任务完成,已启动={}", LOG_TAG, configs.size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("{} 启动加载采集任务失败: {}", LOG_TAG, e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRunning(String configId) {
|
||||||
|
ScheduledFuture<?> f = runningTasks.get(configId);
|
||||||
|
return f != null && !f.isCancelled();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (重新)按配置的间隔调度采集任务。已存在则先取消再重排,实现运行时改间隔。
|
||||||
|
*/
|
||||||
|
public synchronized void scheduleTask(MesXslMcsSyncConfig config) {
|
||||||
|
if (config == null || config.getId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cancelTask(config.getId());
|
||||||
|
long seconds = config.getIntervalSeconds() != null && config.getIntervalSeconds() > 0
|
||||||
|
? config.getIntervalSeconds() : 1L;
|
||||||
|
String configId = config.getId();
|
||||||
|
ScheduledFuture<?> future = taskScheduler.scheduleWithFixedDelay(
|
||||||
|
() -> runOnce(configId), Duration.ofSeconds(seconds));
|
||||||
|
runningTasks.put(configId, future);
|
||||||
|
log.info("{} 采集任务已启动 configId={} 间隔={}s", LOG_TAG, configId, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 取消采集任务(仅停内存定时,不改库)
|
||||||
|
*/
|
||||||
|
public synchronized void cancelTask(String configId) {
|
||||||
|
ScheduledFuture<?> old = runningTasks.remove(configId);
|
||||||
|
if (old != null) {
|
||||||
|
old.cancel(false);
|
||||||
|
log.info("{} 采集任务已停止 configId={}", LOG_TAG, configId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单次采集执行:连接/读取开关守卫 + 调用通用引擎 + 落库结果
|
||||||
|
*/
|
||||||
|
private void runOnce(String configId) {
|
||||||
|
MesXslMcsSyncConfig cfg = syncConfigMapper.selectById(configId);
|
||||||
|
if (cfg == null || cfg.getDelFlag() != null && cfg.getDelFlag() == 1 || !"1".equals(cfg.getStatus())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 中间库未启用或读取开关关闭时安静跳过
|
||||||
|
if (!mcsDataSourceManager.isDbConfigActive() || !mcsDataSourceManager.isReadEnabled()) {
|
||||||
|
log.debug("{} 中间库未就绪或读取关闭,跳过 configId={}", LOG_TAG, configId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
List<MesXslMcsSyncField> fields = syncFieldMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<MesXslMcsSyncField>()
|
||||||
|
.eq(MesXslMcsSyncField::getConfigId, configId)
|
||||||
|
.eq(MesXslMcsSyncField::getDelFlag, 0)
|
||||||
|
.orderByAsc(MesXslMcsSyncField::getSortNo));
|
||||||
|
String result = syncEngine.sync(cfg, fields);
|
||||||
|
// INCR 改为标记位回写后不再维护高水位,仅落库采集结果
|
||||||
|
updateSyncResult(configId, result, null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("{} 采集异常 configId={}: {}", LOG_TAG, configId, e.getMessage(), e);
|
||||||
|
updateSyncResult(configId, "采集失败:" + e.getMessage(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateSyncResult(String id, String result, String watermark) {
|
||||||
|
MesXslMcsSyncConfig update = new MesXslMcsSyncConfig();
|
||||||
|
update.setId(id);
|
||||||
|
update.setLastSyncTime(new Date());
|
||||||
|
update.setLastSyncResult(result != null && result.length() > 480 ? result.substring(0, 480) : result);
|
||||||
|
update.setLastWatermark(watermark);
|
||||||
|
syncConfigMapper.updateById(update);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.util;
|
||||||
|
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.Date;
|
||||||
|
import org.jeecg.common.util.oConvertUtils;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.entity.McsToMesMixAlarm;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipAlarmRecordVO;
|
||||||
|
import org.jeecg.modules.xslmes.mcs.vo.MesXslEquipDowntimeRecordVO;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MCSToMES_MixAlarm 与 MES 设备报警/停机展示 VO 转换
|
||||||
|
*/
|
||||||
|
public final class MesXslMcsMixAlarmConvertUtil {
|
||||||
|
|
||||||
|
public static final String RECORD_TYPE_AUTO = "自动";
|
||||||
|
|
||||||
|
private static final String[] DATE_PATTERNS = {
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy/MM/dd HH:mm:ss",
|
||||||
|
"yyyy-MM-dd HH:mm",
|
||||||
|
"yyyy/MM/dd HH:mm"
|
||||||
|
};
|
||||||
|
|
||||||
|
private MesXslMcsMixAlarmConvertUtil() {}
|
||||||
|
|
||||||
|
public static MesXslEquipAlarmRecordVO toAlarmVo(McsToMesMixAlarm row) {
|
||||||
|
MesXslEquipAlarmRecordVO vo = new MesXslEquipAlarmRecordVO();
|
||||||
|
vo.setId(row.getGuid());
|
||||||
|
vo.setEquipId(row.getEquipId());
|
||||||
|
vo.setEquipName(row.getEquipName());
|
||||||
|
vo.setEquipType(row.getEquipType());
|
||||||
|
vo.setShiftClass(null);
|
||||||
|
vo.setAlarmContent(row.getAlarmInf());
|
||||||
|
vo.setAlarmTime(row.getWriteTime());
|
||||||
|
vo.setRecordType(RECORD_TYPE_AUTO);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MesXslEquipDowntimeRecordVO toDowntimeVo(McsToMesMixAlarm row) {
|
||||||
|
MesXslEquipDowntimeRecordVO vo = new MesXslEquipDowntimeRecordVO();
|
||||||
|
vo.setId(row.getGuid());
|
||||||
|
vo.setEquipId(row.getEquipId());
|
||||||
|
vo.setEquipName(row.getEquipName());
|
||||||
|
vo.setEquipType(row.getEquipType());
|
||||||
|
vo.setShiftClass(null);
|
||||||
|
vo.setDowntimeContent(row.getAlarmInf());
|
||||||
|
vo.setDowntimeStartTime(row.getWriteTime());
|
||||||
|
vo.setDowntimeEndTime(row.getEndTime());
|
||||||
|
vo.setDowntimeDuration(formatDowntimeDuration(row.getWriteTime(), row.getEndTime()));
|
||||||
|
vo.setRecordType(RECORD_TYPE_AUTO);
|
||||||
|
return vo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatDowntimeDuration(Date start, String endStr) {
|
||||||
|
if (start == null || oConvertUtils.isEmpty(endStr)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Date end = parseDateTime(endStr);
|
||||||
|
if (end == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
long diffMs = end.getTime() - start.getTime();
|
||||||
|
if (diffMs < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
long totalMinutes = diffMs / 60000;
|
||||||
|
long hours = totalMinutes / 60;
|
||||||
|
long minutes = totalMinutes % 60;
|
||||||
|
if (hours > 0) {
|
||||||
|
return minutes > 0 ? hours + "小时" + minutes + "分钟" : hours + "小时";
|
||||||
|
}
|
||||||
|
return minutes + "分钟";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Date parseDateTime(String text) {
|
||||||
|
if (oConvertUtils.isEmpty(text)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String trimmed = text.trim();
|
||||||
|
for (String pattern : DATE_PATTERNS) {
|
||||||
|
try {
|
||||||
|
return new SimpleDateFormat(pattern).parse(trimmed);
|
||||||
|
} catch (ParseException ignored) {
|
||||||
|
// try next pattern
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.vo;
|
||||||
|
|
||||||
|
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 org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备报警记录(展示 VO,数据来自 SQL Server MCSToMES_MixAlarm)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "设备报警记录")
|
||||||
|
public class MesXslEquipAlarmRecordVO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "机台编号", width = 15)
|
||||||
|
@Schema(description = "机台编号")
|
||||||
|
private String equipId;
|
||||||
|
|
||||||
|
@Excel(name = "机台名称", width = 15)
|
||||||
|
@Schema(description = "机台名称")
|
||||||
|
private String equipName;
|
||||||
|
|
||||||
|
@Excel(name = "机台类型", width = 15)
|
||||||
|
@Schema(description = "机台类型")
|
||||||
|
private String equipType;
|
||||||
|
|
||||||
|
@Excel(name = "班次", width = 12)
|
||||||
|
@Schema(description = "班次")
|
||||||
|
private String shiftClass;
|
||||||
|
|
||||||
|
@Excel(name = "报警内容", width = 40)
|
||||||
|
@Schema(description = "报警内容")
|
||||||
|
private String alarmContent;
|
||||||
|
|
||||||
|
@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 alarmTime;
|
||||||
|
|
||||||
|
@Excel(name = "类型", width = 12)
|
||||||
|
@Schema(description = "类型(自动/人工)")
|
||||||
|
private String recordType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package org.jeecg.modules.xslmes.mcs.vo;
|
||||||
|
|
||||||
|
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 org.jeecgframework.poi.excel.annotation.Excel;
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备停机记录(展示 VO,数据来自 SQL Server MCSToMES_MixAlarm)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "设备停机记录")
|
||||||
|
public class MesXslEquipDowntimeRecordVO implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Schema(description = "主键")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Excel(name = "机台编号", width = 15)
|
||||||
|
@Schema(description = "机台编号")
|
||||||
|
private String equipId;
|
||||||
|
|
||||||
|
@Excel(name = "机台名称", width = 15)
|
||||||
|
@Schema(description = "机台名称")
|
||||||
|
private String equipName;
|
||||||
|
|
||||||
|
@Excel(name = "机台类型", width = 15)
|
||||||
|
@Schema(description = "机台类型")
|
||||||
|
private String equipType;
|
||||||
|
|
||||||
|
@Excel(name = "班次", width = 12)
|
||||||
|
@Schema(description = "班次")
|
||||||
|
private String shiftClass;
|
||||||
|
|
||||||
|
@Excel(name = "停机内容", width = 40)
|
||||||
|
@Schema(description = "停机内容")
|
||||||
|
private String downtimeContent;
|
||||||
|
|
||||||
|
@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 downtimeStartTime;
|
||||||
|
|
||||||
|
@Excel(name = "停机结束时间", width = 20)
|
||||||
|
@Schema(description = "停机结束时间")
|
||||||
|
private String downtimeEndTime;
|
||||||
|
|
||||||
|
@Excel(name = "停机时长", width = 15)
|
||||||
|
@Schema(description = "停机时长")
|
||||||
|
private String downtimeDuration;
|
||||||
|
|
||||||
|
@Excel(name = "类型", width = 12)
|
||||||
|
@Schema(description = "类型(自动/人工)")
|
||||||
|
private String recordType;
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslAutoSmallMaterialPlanMaintain;
|
||||||
|
|
||||||
|
public interface IMesXslAutoSmallMaterialPlanMaintainService
|
||||||
|
extends IService<MesXslAutoSmallMaterialPlanMaintain> {
|
||||||
|
void saveAllRows(List<MesXslAutoSmallMaterialPlanMaintain> rows);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MES 设备管理 / 质量管理主数据删除前引用校验。
|
||||||
|
*/
|
||||||
|
public interface IMesXslDeleteReferenceService {
|
||||||
|
|
||||||
|
String validateEquipmentCategoryDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateEquipmentTypeDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateEquipmentPartDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateEquipmentSubPartDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateInspectMaintainItemDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateEquipmentLedgerDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateManufacturerDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateSparePartsCategoryDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateDowntimeMainTypeDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateDowntimeTypeDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateEquipInspectConfigDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateRubberQuickTestTypeDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateRubberQuickTestDataPointDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateRubberQuickTestMethodDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateRubberQuickTestStdDelete(Collection<String> ids);
|
||||||
|
|
||||||
|
String validateRubberSmallLockReasonDelete(Collection<String> ids);
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package org.jeecg.modules.xslmes.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import java.util.List;
|
||||||
|
import org.jeecg.modules.xslmes.entity.MesXslManualSmallMaterialPlanMaintain;
|
||||||
|
|
||||||
|
public interface IMesXslManualSmallMaterialPlanMaintainService
|
||||||
|
extends IService<MesXslManualSmallMaterialPlanMaintain> {
|
||||||
|
void saveAllRows(List<MesXslManualSmallMaterialPlanMaintain> rows);
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user