diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..e69de29
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 5b0aa08..3582d6e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,14 @@
{
- "java.compile.nullAnalysis.mode": "automatic",
- "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable",
- "java.configuration.updateBuildConfiguration": "interactive"
-}
\ No newline at end of file
+ "java.compile.nullAnalysis.mode": "automatic",
+ "java.jdt.ls.vmargs": "-XX:+UseParallelGC -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -Dsun.zip.disableMemoryMapping=true -Xmx4G -Xms100m -Xlog:disable",
+ "java.import.maven.enabled": true,
+ "java.configuration.updateBuildConfiguration": "automatic",
+ "java.jdt.ls.java.home": "C:\\Program Files\\Java\\jdk-17",
+ "java.configuration.runtimes": [
+ {
+ "name": "JavaSE-17",
+ "path": "C:\\Program Files\\Java\\jdk-17",
+ "default": true
+ }
+ ]
+}
diff --git a/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..8848383
--- /dev/null
+++ b/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,2 @@
+com.yomahub.liteflow.springboot.config.LiteflowPropertyAutoConfiguration
+com.yomahub.liteflow.springboot.config.LiteflowMainAutoConfiguration
\ No newline at end of file
diff --git a/docs/MES-XSL-客户到仓库-当前实现说明.md b/docs/MES-XSL-客户到仓库-当前实现说明.md
new file mode 100644
index 0000000..30c816a
--- /dev/null
+++ b/docs/MES-XSL-客户到仓库-当前实现说明.md
@@ -0,0 +1,220 @@
+# MES XSL「客户到仓库」当前实现说明
+
+本文档只描述**当前设计与实现**:数据表、字段含义、后端与前端逻辑、实体间关系、约束与使用方式,不涉及历史变更过程。
+
+---
+
+## 一、涉及的数据表
+
+| 表名 | 作用 |
+|------|------|
+| `mes_xsl_customer` | 客户主数据 |
+| `mes_xsl_warehouse` | 仓库主数据(通过分类 + 客户/供应商字段实现「客户库 / 供应商库」) |
+| `mes_xsl_supplier` | 供应商主数据 |
+| `mes_xsl_unit` | 单位主数据(分类挂在系统分类字典上) |
+| `sys_category` | 系统「分类字典」:仓库分类树根编码 `XSLMES_WH`,单位分类树根编码 `XSLMES_UNIT` |
+
+---
+
+## 二、字段说明
+
+### 2.1 `mes_xsl_customer`
+
+| 字段 | 说明 |
+|------|------|
+| `id` | 主键 |
+| `customer_code` | 客户编码 |
+| `customer_name` | 客户名称 |
+| `customer_short_name` | 客户简称 |
+| `customer_region` | 区域,数据字典 `xslmes_customer_region` |
+| `erp_code` | ERP 编码 |
+| `status` | 业务状态,字典 `xslmes_customer_status` |
+| `del_flag` | 逻辑删除(0 正常 1 已删除) |
+| `customer_desc` | 描述 |
+| `iz_enable` | 是否启用(与状态等业务规则配合) |
+| `create_by` / `create_time` / `update_by` / `update_time` | 审计字段(继承 Jeecg 基类) |
+| `tenant_id` | 租户 ID |
+
+### 2.2 `mes_xsl_warehouse`(客户 / 供应商与仓库的衔接点)
+
+| 字段 | 说明 |
+|------|------|
+| `id` | 主键 |
+| `warehouse_code` | 仓库编码 |
+| `warehouse_name` | 仓库名称 |
+| `warehouse_category` | **仓库分类**:存储 **`sys_category.id`**;该分类必须属于根编码 **`XSLMES_WH`** 下的子树 |
+| `erp_code` | ERP 编码 |
+| `status` | 启用/停用,字典 **`xslmes_unit_status`** |
+| `customer_id` | 客户主键;**仅当**分类节点 `code = XSLMES_WH_F2_KH`(客户库)时必填且有意义 |
+| `customer_short_name` | 客户简称(展示/冗余) |
+| `supplier_id` | 供应商主键;**仅当**分类节点 `code = XSLMES_WH_F2_GYS`(供应商库)时必填且有意义 |
+| `supplier_short_name` | 供应商简称(展示/冗余) |
+| `del_flag` | 逻辑删除 |
+| 审计字段、`tenant_id` | 同 Jeecg 惯例 |
+
+**索引:** `warehouse_code`、`warehouse_category`。
+
+### 2.3 `sys_category`(与仓库、单位相关的用法)
+
+- **仓库**:根节点 `code = XSLMES_WH`(常量 `MesXslWarehouseCategory.ROOT_CODE`)。`mes_xsl_warehouse.warehouse_category` 存任意该树下的 **`id`**(通常选叶子节点)。
+- **单位**:根节点 `code = XSLMES_UNIT`。`mes_xsl_unit.category_id` 存对应 **`id`**。
+
+**与仓库校验相关的分类编码(后端写死):**
+
+| `sys_category.code` | 含义 | 业务规则 |
+|---------------------|------|----------|
+| `XSLMES_WH_F2_KH` | 客户库 | 保存仓库时 **必须** 有 `customer_id` |
+| `XSLMES_WH_F2_GYS` | 供应商库 | 保存仓库时 **必须** 有 `supplier_id` |
+
+当前种子树结构为:**根 `XSLMES_WH` → 一楼库 / 二楼仓库 → 各叶子**(成品库、待检库、客户库、供应商库等);运维可在该根下扩展子节点(需具备分类维护权限)。
+
+### 2.4 `mes_xsl_supplier`
+
+| 字段 | 说明 |
+|------|------|
+| `id` | 主键 |
+| `supplier_code` | 编码 |
+| `supplier_name` | 名称 |
+| `supplier_short_name` | 简称 |
+| `erp_code` | ERP 编码 |
+| `remark` | 备注 |
+| `status` | 状态,字典 `xslmes_supplier_status` |
+| `del_flag` | 逻辑删除 |
+| 审计字段、`tenant_id` | 同 Jeecg 惯例 |
+
+### 2.5 `mes_xsl_unit`
+
+| 字段 | 说明 |
+|------|------|
+| `id` | 主键 |
+| `unit_code` / `unit_name` | 单位编码、名称 |
+| `erp_code` | ERP 编码 |
+| `category_id` | **所属分类**:`sys_category.id`,且属于根 **`XSLMES_UNIT`** 子树 |
+| `unit_desc` | 描述 |
+| `status` | 字典 `xslmes_unit_status` |
+| `del_flag` | 逻辑删除 |
+| 审计字段、`tenant_id` | 同 Jeecg 惯例 |
+
+---
+
+## 三、实现逻辑
+
+### 3.1 仓库保存与更新(后端)
+
+实现类:`MesXslWarehouseServiceImpl`,在 `save` / `updateById` 时统一处理。
+
+1. **按分类清理客户 / 供应商(`normalizePartners`)**
+ - 未选分类:清空 `customer_id`、`customer_short_name`、`supplier_id`、`supplier_short_name`。
+ - 已选分类:根据 `warehouse_category` 查询 `sys_category.code`。
+ - 若不是 **客户库**(`XSLMES_WH_F2_KH`):清空客户相关两字段。
+ - 若不是 **供应商库**(`XSLMES_WH_F2_GYS`):清空供应商相关两字段。
+ - 目的:切换仓库类型后不留错误的客户或供应商数据。
+
+2. **按分类校验(`validatePartners`)**
+ - **客户库**:`customer_id` 为空则抛出业务异常:「仓库分类为客户库时,请选择客户」。
+ - **供应商库**:`supplier_id` 为空则抛出类似提示。
+
+3. **分类编码查询**
+ - `MesXslWarehouseMapper.queryCategoryCodeById`:`SELECT code FROM sys_category WHERE id = ?`。
+
+### 3.2 字典与展示
+
+- `MesXslWarehouse.warehouse_category` 使用 `@Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")`,列表/详情按 **分类名称** 展示。
+- `MesXslUnit.category_id` 同样指向 `sys_category`。
+
+### 3.3 前端(仓库)
+
+- 菜单路由:`/xslmes/mesXslWarehouse`,列表组件:`MesXslWarehouseList`。
+- 左侧分类树:加载根编码 **`XSLMES_WH`** 的分类树(系统分类字典接口,与 `JCategorySelect` 的 `pcode` 一致)。
+- 列表筛选与查询参数需与后端 `QueryGenerator` 约定一致(如 `warehouseCategory`、多选场景下的 `warehouseCategory_MultiString` 等)。
+- 侧栏 **新增 / 编辑 / 删除分类**:调用 `/sys/category` 下标准增删改接口;按钮权限为 `xslmes:mes_xsl_warehouse_category:add|edit|delete`。
+
+### 3.4 前端(单位)
+
+- 分类选择:`JCategorySelect`,`pcode: XSLMES_UNIT`。
+- 按左侧分类筛选列表时,后端通过 **递归查询子分类 id**(`MesXslUnitService.listDescendantCategoryIds` / `MesXslUnitMapper`)过滤数据;依赖 **MySQL 8** 递归 CTE。
+
+### 3.5 接口前缀(REST)
+
+| 模块 | 路径前缀 |
+|------|----------|
+| 客户 | `/xslmes/mesXslCustomer` |
+| 仓库 | `/xslmes/mesXslWarehouse` |
+| 供应商 | `/xslmes/mesXslSupplier` |
+| 单位 | `/xslmes/mesXslUnit` |
+
+具体方法为 Jeecg 标准 CRUD(如列表、新增、编辑、删除、导入导出等),见各 `Controller`。
+
+---
+
+## 四、关联关系
+
+数据库层**不强制外键**时,由应用与数据约定保证引用有效。
+
+```mermaid
+erDiagram
+ sys_category_WH["sys_category(根 XSLMES_WH)"] ||--o{ mes_xsl_warehouse : "warehouse_category = id"
+ mes_xsl_customer ||--o{ mes_xsl_warehouse : "customer_id = id(客户库)"
+ mes_xsl_supplier ||--o{ mes_xsl_warehouse : "supplier_id = id(供应商库)"
+ sys_category_UNIT["sys_category(根 XSLMES_UNIT)"] ||--o{ mes_xsl_unit : "category_id = id"
+```
+
+**语义说明:**
+
+- 一条仓库记录对应 **一个** `warehouse_category`(`sys_category` 的一行)。
+- **客户库**:该仓库在业务上绑定 **一个** 客户(`customer_id` → `mes_xsl_customer.id`)。
+- **供应商库**:绑定 **一个** 供应商(`supplier_id` → `mes_xsl_supplier.id`)。
+- 其它分类:客户、供应商字段应在保存时被清空,不参与当前分类下的业务含义。
+
+---
+
+## 五、功能限制与注意点
+
+1. **`warehouse_category` 必须是有效的 `sys_category.id`**,且业务上应选用 `XSLMES_WH` 树下节点;若 id 不存在或 `code` 查询不到,客户库/供应商库校验可能无法按预期触发。
+2. **客户库与供应商库互斥**:非客户库会自动清空客户字段,非供应商库会自动清空供应商字段;不应依赖「改分类后仍保留另一侧 ID」。
+3. **每条仓库仅一个客户、一个供应商字段**:与车辆等业务里「多客户 id 逗号拼接」等模型不同,仓库行是单值引用。
+4. **多租户**:若启用 SaaS 租户隔离,`mes_xsl_*` 等表需在 MyBatis 租户配置中注册,否则会出现串租或查不到数据。
+5. **单位分类树筛选**:依赖 MySQL 8 递归语法;低于 8.0 的环境需调整实现。
+6. **前端联调**:`VITE_GLOB_API_URL` 必须与后端 `context-path`(如 `/jeecg-boot`)一致,否则接口路径错误。
+
+---
+
+## 六、使用方法
+
+### 6.1 环境
+
+- 后端:`jeecg-system-start` 启动,数据库脚本由项目 **Flyway** 随应用升级自动执行,保证上述表与 `sys_category` 种子存在。
+- 浏览器访问前端,使用已配置 **MES XSL** 菜单及仓库、客户、供应商、单位等权限的账号。
+
+### 6.2 维护主数据
+
+1. **客户**:菜单「客户管理」,维护 `mes_xsl_customer`。
+2. **供应商**:菜单「供应商管理」,维护 `mes_xsl_supplier`。
+3. **单位**:菜单「单位管理」,分类从 **`XSLMES_UNIT`** 树选择;可在侧栏维护分类(与仓库侧栏模式类似,权限依项目配置)。
+
+### 6.3 维护仓库分类树
+
+1. 打开 **仓库管理**。
+2. 在左侧分类区域使用新增/编辑/删除(需 `xslmes:mes_xsl_warehouse_category:*` 权限)。
+3. 新建分类应挂在 **`XSLMES_WH`** 根之下,避免与其它业务根混淆。
+
+### 6.4 新建「客户库」仓库
+
+1. 新增仓库,**仓库分类** 选择 **客户库**(`code` 为 `XSLMES_WH_F2_KH` 的节点)。
+2. **必须** 选择客户并保存。
+3. 若之后改为非客户库分类,保存后客户相关字段会被后端清空。
+
+### 6.5 新建「供应商库」仓库
+
+将分类选为 **供应商库**(`XSLMES_WH_F2_GYS`),**必须** 选择供应商;改为其它分类时供应商字段会被清空。
+
+### 6.6 权限说明(仓库相关示例)
+
+- 仓库 CRUD 等:`xslmes:mes_xsl_warehouse:add`、`edit`、`delete`、`deleteBatch`、`exportXls`、`importExcel`、`updateStatus` 等。
+- 仓库分类维护:`xslmes:mes_xsl_warehouse_category:add`、`edit`、`delete`。
+
+实际以系统「菜单管理 / 角色授权」中配置为准。
+
+---
+
+*文档描述与当前代码、表结构一致;若常量 `MesXslWarehouseCategory` 或表字段有调整,请以仓库内源码与数据库为准同步更新本文档。*
diff --git a/docs/MES-XSL-客户到仓库功能模块说明.md b/docs/MES-XSL-客户到仓库功能模块说明.md
new file mode 100644
index 0000000..d787e2b
--- /dev/null
+++ b/docs/MES-XSL-客户到仓库功能模块说明.md
@@ -0,0 +1,309 @@
+# MES XSL「客户到仓库」功能模块说明
+
+本文档说明 Git 分支 **`客户到仓库功能模块`** 所承载的 MES XSL 业务能力,重点覆盖 **客户主数据**、**仓库管理(含客户库 / 供应商库)**、以及配套的 **单位分类改造**。文中表结构以 Flyway 脚本与实体类为准;实现逻辑以当前工作区代码为准。
+
+---
+
+## 1. 分支与代码范围说明
+
+### 1.1 相对 `main` 已提交的内容
+
+在当前仓库中执行 `git diff main --stat` 可见:分支相对 `main` **已提交**的改动主要集中在 **工程脚手架与环境**,例如:
+
+- 后端:`jeecg-boot-module/pom.xml` 引入子模块、`jeecg-system-start/pom.xml` 依赖、`MybatisPlusSaasConfig` 租户表配置等。
+- 前端:`jeecgboot-vue3` 的 `.env.*`、`vite` 代理、`axios`、表单 `useForm` 等。
+
+**结论:** 若仅看「已提交到 Git 的差异」,并不会完整反映「客户、仓库、单位」等 MES 业务表与前后端页面;这些能力的**主要交付物**位于工作区中的:
+
+| 区域 | 路径(仓库根下) |
+|------|------------------|
+| 后端模块 | `jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/` |
+| 数据库迁移 | `jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_*__mes_xsl_*.sql` |
+| 前端页面 | `jeecgboot-vue3/src/views/xslmes/` |
+
+文档以下章节按**完整业务能力**描述;合并到 `main` 或发版前请确保上述目录已 **add / commit**,并与 Flyway 版本一致。
+
+### 1.2 运行与依赖提示
+
+- **MySQL**:建议 **8.0+**(单位列表按分类树筛选时使用递归 CTE,见 `MesXslUnitMapper`)。
+- **Flyway**:按版本号顺序执行;仓库分类以 **`V3.9.2_27`** 为界,由字典 `item_value` 迁移为 **`sys_category.id`**(见下文)。
+- **API 前缀**:前端 `VITE_GLOB_API_URL` 需与后端 `context-path`(如 `/jeecg-boot`)一致,否则接口 404。
+
+---
+
+## 2. 数据表与字段
+
+### 2.1 `mes_xsl_customer`(客户主数据)
+
+客户是「客户库」仓库行的关联目标。
+
+| 字段 | 类型(约) | 说明 |
+|------|------------|------|
+| `id` | varchar(36) | 主键 |
+| `customer_code` | varchar(100) | 客户编码 |
+| `customer_name` | varchar(200) | 客户名称 |
+| `customer_short_name` | varchar(…) | 客户简称(后续脚本扩展,与实体一致) |
+| `customer_region` | varchar(32) | 区域,字典 `xslmes_customer_region` |
+| `erp_code` | varchar(100) | ERP 编码 |
+| `status` | varchar(10) | 业务状态,字典 `xslmes_customer_status`(0 启用 1 停用等) |
+| `del_flag` | tinyint | 逻辑删除(MyBatis-Plus `@TableLogic`) |
+| `customer_desc` | varchar(500) | 描述 |
+| `iz_enable` | tinyint | 是否启用(与服务端状态同步) |
+| `create_by` / `create_time` / `update_by` / `update_time` | 审计字段 | Jeecg 标准 |
+| `tenant_id` | int | 租户 |
+
+**初始化脚本:** `V3.9.2_4__mes_xsl_customer.sql` 及后续 `V3.9.2_5/6/20/21/23` 等补丁。
+
+---
+
+### 2.2 `mes_xsl_warehouse`(仓库,**客户到仓库的核心表**)
+
+| 字段 | 类型(约) | 说明 |
+|------|------------|------|
+| `id` | varchar(36) | 主键 |
+| `warehouse_code` | varchar(100) | 仓库编码 |
+| `warehouse_name` | varchar(200) | 仓库名称 |
+| `warehouse_category` | varchar(36) | **仓库分类**:存 **`sys_category.id`**,根节点编码为 **`XSLMES_WH`**(`V3.9.2_27` 后) |
+| `erp_code` | varchar(100) | ERP 编码 |
+| `status` | varchar(10) | 状态,字典 **`xslmes_unit_status`**(0 启用 1 停用) |
+| `customer_id` | varchar(36) | **客户主键**,仅在分类为 **客户库**(`code = XSLMES_WH_F2_KH`)时有意义 |
+| `customer_short_name` | varchar(200) | 客户简称展示 |
+| `supplier_id` | varchar(36) | **供应商主键**,仅在分类为 **供应商库**(`code = XSLMES_WH_F2_GYS`)时有意义 |
+| `supplier_short_name` | varchar(100) | 供应商简称展示 |
+| `del_flag` | tinyint | 逻辑删除 |
+| 审计字段、`tenant_id` | | 同 Jeecg 惯例 |
+
+**历史说明:** `V3.9.2_26` 建表时 `warehouse_category` 注释为字典 `xslmes_warehouse_category` 的 `item_value`;**`V3.9.2_27` 执行后**,该列已批量 `UPDATE` 为对应 **`sys_category` 主键**,列类型改为 `varchar(36)`。字典 `xslmes_warehouse_category` 可能仍存在于库中,**业务应以 `sys_category` 为准**,避免混用。
+
+**索引:** `warehouse_code`、`warehouse_category`。
+
+---
+
+### 2.3 `sys_category`(系统分类字典,仓库与单位共用机制)
+
+仓库与单位分类均挂在 **`sys_category`** 树上,通过根节点 **`code`** 区分业务域:
+
+| 根编码 | 业务含义 | 典型脚本 |
+|--------|----------|----------|
+| **`XSLMES_WH`** | MES 仓库分类整棵树 | `V3.9.2_27__mes_xsl_warehouse_sys_category.sql` |
+| **`XSLMES_UNIT`** | MES 单位分类整棵树 | `V3.9.2_29__mes_xsl_unit_sys_category.sql` |
+
+**仓库侧关键叶子节点编码(业务常量硬编码校验):**
+
+| `code` | 名称(种子数据) | 用途 |
+|--------|------------------|------|
+| `XSLMES_WH_F2_KH` | 客户库 | 必须绑定 **`customer_id`** |
+| `XSLMES_WH_F2_GYS` | 供应商库 | 必须绑定 **`supplier_id`** |
+
+其它叶子(如一楼成品库、二楼原材料库等)**不要求**填写客户或供应商;后端在保存前会 **清空** 无关的客户/供应商字段,防止切换分类后残留脏数据。
+
+**树结构(种子):** 根 `XSLMES_WH` → 一楼库 `XSLMES_WH_F1` / 二楼仓库 `XSLMES_WH_F2` → 各叶子分类(成品库、待检库、客户库、供应商库等),详见 `V3.9.2_27` 中 `INSERT`。
+
+---
+
+### 2.4 `mes_xsl_supplier`(供应商)
+
+供应商主数据,供「供应商库」类型仓库引用。
+
+主要字段:`supplier_code`、`supplier_name`、`supplier_short_name`、`erp_code`、`remark`、`status`(`xslmes_supplier_status`)、`del_flag`、`tenant_id` 及 Jeecg 基类字段。脚本见 `V3.9.2_11` 等。
+
+---
+
+### 2.5 `mes_xsl_unit`(单位)
+
+| 字段 | 说明 |
+|------|------|
+| `category_id` | **`sys_category.id`**,根编码 **`XSLMES_UNIT`**(`V3.9.2_29` 后) |
+
+**`mes_xsl_unit_category`:** `V3.9.2_29` 将数据迁入 `sys_category` 后 **已 `DROP`**,单位侧栏维护方式与仓库侧一致(分类字典 API)。
+
+---
+
+### 2.6 其它相关表(同一 MES 模块,扩展阅读)
+
+- **`mes_xsl_vehicle`**:车辆;含 `customer_ids`(多选逗号)、`supplier_id` 等,与主数据客户/供应商有关联,但不改变「仓库行绑定单一客户/供应商」的规则。
+- **`mes_xsl_instrument`**:仪器等独立主数据。
+
+---
+
+## 3. 实现逻辑
+
+### 3.1 仓库保存 / 更新(客户库、供应商库)
+
+类:`MesXslWarehouseServiceImpl`。
+
+1. **`normalizePartners`**(保存前规范化)
+ - 若未选分类:清空客户、供应商相关字段。
+ - 否则根据 `warehouse_category`(`sys_category.id`)查询 **`code`**:
+ - 非 **客户库**(`XSLMES_WH_F2_KH`):清空 `customer_id`、`customer_short_name`。
+ - 非 **供应商库**(`XSLMES_WH_F2_GYS`):清空 `supplier_id`、`supplier_short_name`。
+ - 目的:从「客户库」改成其它分类时,不保留旧客户信息。
+
+2. **`validatePartners`**(校验)
+ - 分类为 **客户库**:`customer_id` 不能为空,否则抛出 `JeecgBootException("仓库分类为客户库时,请选择客户")`。
+ - 分类为 **供应商库**:`supplier_id` 不能为空,否则抛出类似供应商提示。
+
+3. **分类编码查询**
+ - `MesXslWarehouseMapper.queryCategoryCodeById`:`SELECT code FROM sys_category WHERE id = ?`
+ - 业务判断常量:`MesXslWarehouseCategory.CUSTOMER_CATEGORY_CODE` / `SUPPLIER_CATEGORY_CODE`。
+
+### 3.2 实体与字典翻译
+
+- `MesXslWarehouse.warehouseCategory` 使用 `@Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")`,列表/表单显示分类名称。
+
+### 3.3 前端仓库页
+
+- 列表路由:`/xslmes/mesXslWarehouse`(菜单 `V3.9.2_26` 种子)。
+- 左侧分类树:调用系统接口加载根编码 **`XSLMES_WH`** 的子树(与 `/sys/category/loadTreeRoot` 等标准分类字典用法一致)。
+- 列表查询字段与 `QueryGenerator` 规则一致:如 `warehouseCategory`、`warehouseCategory_MultiString` 等(用于叶子或父级筛选)。
+- 侧栏 **新增 / 编辑 / 删除分类**:走 `/sys/category/add|edit|delete`,需按钮权限(见下节)。
+
+### 3.4 前端单位页(与仓库同模式)
+
+- `category_id` 使用 `JCategorySelect`,`pcode: XSLMES_UNIT`。
+- 列表树筛选使用 `MesXslUnitService.listDescendantCategoryIds`(递归子分类),依赖 MySQL 8 递归 CTE。
+
+---
+
+## 4. 关联关系(逻辑模型)
+
+以下为 **逻辑关联**(脚本未强制数据库外键时,由应用层保证)。
+
+```mermaid
+erDiagram
+ sys_category_WH["sys_category (根 XSLMES_WH)"] ||--o{ mes_xsl_warehouse : "warehouse_category = id"
+ mes_xsl_customer ||--o{ mes_xsl_warehouse : "customer_id = id (仅客户库)"
+ mes_xsl_supplier ||--o{ mes_xsl_warehouse : "supplier_id = id (仅供应商库)"
+ sys_category_UNIT["sys_category (根 XSLMES_UNIT)"] ||--o{ mes_xsl_unit : "category_id = id"
+```
+
+**要点:**
+
+- **多对一(N:1)**:多个仓库行可对应同一客户或同一供应商(视业务是否允许重复配置而定);每条仓库行 **最多一个** `customer_id` 与一个 `supplier_id`,且由分类决定哪一侧生效。
+- **客户库**:`mes_xsl_warehouse.customer_id` → `mes_xsl_customer.id`。
+- **供应商库**:`mes_xsl_warehouse.supplier_id` → `mes_xsl_supplier.id`。
+
+---
+
+## 5. 权限与菜单
+
+### 5.1 仓库菜单(节选)
+
+- 菜单 ID `1900000000000000380`:仓库管理,前端组件 `xslmes/mesXslWarehouse/MesXslWarehouseList`。
+- 按钮权限示例:
+ - `xslmes:mes_xsl_warehouse:add|edit|delete|deleteBatch|exportXls|importExcel|updateStatus`
+- **分类维护按钮**(`V3.9.2_28`):
+ - `xslmes:mes_xsl_warehouse_category:add`
+ - `xslmes:mes_xsl_warehouse_category:edit`
+ - `xslmes:mes_xsl_warehouse_category:delete`
+
+管理员角色在种子脚本中已授权一批 `sys_role_permission`(以脚本中 `role_id` 为准;生产环境需按实际角色分配)。
+
+### 5.2 客户菜单
+
+- 父模块「MES XSL」与客户列表、客户 CRUD 按钮权限见 `V3.9.2_4` 及 `V3.9.2_23/24/25` 等。
+
+### 5.3 后端接口前缀
+
+| 资源 | `@RequestMapping` 前缀 |
+|------|-------------------------|
+| 客户 | `/xslmes/mesXslCustomer` |
+| 仓库 | `/xslmes/mesXslWarehouse` |
+| 供应商 | `/xslmes/mesXslSupplier` |
+| 单位 | `/xslmes/mesXslUnit` |
+| 车辆 | `/xslmes/mesXslVehicle` |
+
+(Jeecg 标准 CRUD:`/list`、`/add`、`/edit`、`/delete` 等,具体见各 `Controller`。)
+
+---
+
+## 6. 功能限制与注意点
+
+1. **分类存储形态**
+ - 必须使用 **`sys_category.id`** 写入 `warehouse_category`。若手工写入旧字典值(如 `CUSTOMER`),字典翻译与后端 `code` 判断会不一致。
+
+2. **客户库 / 供应商库互斥展示**
+ - 后端会清掉「当前分类不需要」的一方字段;**不能**指望在「客户库」下仍保留供应商 ID。
+
+3. **单客户 / 单供应商 per 仓库行**
+ - 与车辆表 `customer_ids` 多选逗号不同,**仓库表为单值 `customer_id`**,表示该仓库行归属单一客户(业务设计如此)。
+
+4. **分类 id 非法或缺失**
+ - 若 `warehouse_category` 指向不存在的 `sys_category`,`queryCategoryCodeById` 可能返回 `null`,此时不会按客户库/供应商库做强校验;应避免脏数据,建议在界面只选合法分类。
+
+5. **字典 `xslmes_warehouse_category`**
+ - `V3.9.2_26` 曾用于初始化;**`V3.9.2_27` 后业务以 `sys_category` 为准**。报表或旧报表若仍读字典需改造。
+
+6. **租户**
+ - `MybatisPlusSaasConfig` 中需包含 `mes_xsl_*` 等业务表,否则多租户下数据隔离异常。
+
+7. **单位分类迁移**
+ - 执行 `V3.9.2_29` 后 **`mes_xsl_unit_category` 表删除**,旧代码中依赖该表的接口需已全部移除。
+
+---
+
+## 7. 使用方法(业务与运维)
+
+### 7.1 初始化数据库
+
+1. 启动带 Flyway 的 `jeecg-system-start`,确保 **`V3.9.2_26` → `V3.9.2_27` → `V3.9.2_28` → `V3.9.2_29`**(及客户相关 `V3.9.2_4` 等)按序成功执行。
+2. 验证 `sys_category` 中存在 `code = 'XSLMES_WH'`、`'XSLMES_UNIT'` 的根节点及子节点。
+3. 验证 `mes_xsl_warehouse.warehouse_category` 列为 `varchar(36)` 且存量数据已为 **36 位 id**(由 27 脚本迁移)。
+
+### 7.2 配置客户与供应商主数据
+
+1. 菜单 **MES XSL → 客户管理**:维护 `mes_xsl_customer`。
+2. **供应商管理**:维护 `mes_xsl_supplier`。
+3. 确保客户/供应商状态与业务规则一致(启用等),以便仓库弹窗可选。
+
+### 7.3 维护仓库分类树
+
+1. 进入 **仓库管理** 页面。
+2. 在侧栏使用 **新增 / 编辑 / 删除分类**(需具备 `xslmes:mes_xsl_warehouse_category:*` 权限)。
+3. 新增节点应挂在 **`XSLMES_WH`** 树下,避免与其它根混淆。
+
+### 7.4 新建「客户库」仓库
+
+1. 新增仓库,**仓库分类** 选择 **客户库**(`XSLMES_WH_F2_KH` 对应节点)。
+2. **必须选择客户**;保存后 `customer_id`、`customer_short_name` 写入。
+3. 若改为非客户库分类,保存后客户字段会被后端清空。
+
+### 7.5 新建「供应商库」仓库
+
+与客户库对称:分类选 **供应商库**,**必须选择供应商**。
+
+### 7.6 开发与联调
+
+1. 后端引入模块:`jeecg-module-xslmes` 已被 `jeecg-system-start` 依赖(以当前 `pom` 为准)。
+2. 修改接口后执行 **`mvn compile`** 并重启,避免 Controller 未编译导致 404。
+3. 前端 `.env.development` 中 API 地址与后端 `context-path` 一致。
+
+---
+
+## 8. Flyway 脚本索引(MES XSL 相关)
+
+可按文件名在仓库中搜索;下列为当前常见的 `mes_xsl` 迁移(版本号以实际仓库为准):
+
+| 脚本 | 主题 |
+|------|------|
+| `V3.9.2_4` | 客户表、字典、菜单 |
+| `V3.9.2_5` ~ `V3.9.2_7` | 客户简称、同步状态、车辆 |
+| `V3.9.2_8` ~ `V3.9.2_9` | 单位表、种子 |
+| `V3.9.2_10` ~ `V3.9.2_18` | 车辆/单位/仪器/状态等补丁 |
+| `V3.9.2_11` | 供应商 |
+| `V3.9.2_20` ~ `V3.9.2_25` | 客户租户、字典、菜单按钮、is_leaf 等 |
+| **`V3.9.2_26`** | **仓库表、仓库字典、菜单与按钮** |
+| **`V3.9.2_27`** | **仓库分类 → sys_category,数据迁移** |
+| **`V3.9.2_28`** | **仓库分类维护按钮权限** |
+| **`V3.9.2_29`** | **单位分类 → sys_category,删除旧表** |
+
+---
+
+## 9. 文档维护
+
+- 若表结构或常量编码变更,请同步修改:`MesXslWarehouseCategory`、`Flyway` 种子、`sys_category` 根/子节点编码。
+- 合并分支前建议再执行一次:`git status` 确认 `jeecg-module-xslmes` 与 `V3.9.2_*` 脚本均已纳入版本控制。
+
+---
+
+*文档生成依据:分支 `客户到仓库功能模块` 工作区代码与 Flyway 脚本;相对 `main` 的 Git 提交差异请单独以 `git log` / `git diff` 为准。*
diff --git a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
index 4228c77..5bc4d02 100644
--- a/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
+++ b/jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/config/mybatis/MybatisPlusSaasConfig.java
@@ -51,7 +51,7 @@ public class MybatisPlusSaasConfig {
* 3.菜单表、租户表不做租户隔离
* 4.通过拦截器MybatisInterceptor实现,增删改查数据 自动注入租户ID
*/
- public static final Boolean OPEN_SYSTEM_TENANT_CONTROL = false;
+ public static final Boolean OPEN_SYSTEM_TENANT_CONTROL = true;
/**
* 哪些表需要做多租户 表需要添加一个字段 tenant_id
@@ -80,6 +80,11 @@ public class MybatisPlusSaasConfig {
TENANT_TABLE.add("airag_knowledge");
TENANT_TABLE.add("airag_knowledge_doc");
TENANT_TABLE.add("airag_model");
+ TENANT_TABLE.add("mes_xsl_customer");
+ TENANT_TABLE.add("mes_xsl_vehicle");
+ TENANT_TABLE.add("mes_xsl_unit");
+ TENANT_TABLE.add("mes_xsl_supplier");
+ TENANT_TABLE.add("mes_xsl_instrument");
}
//2.示例测试
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml
new file mode 100644
index 0000000..19b8ebd
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/pom.xml
@@ -0,0 +1,22 @@
+
+
+
+ jeecg-boot-module
+ org.jeecgframework.boot3
+ 3.9.1
+
+ 4.0.0
+
+ jeecg-module-xslmes
+ jeecg-module-xslmes
+ MES XSL 业务模块(Java 包:org.jeecg.modules.xslmes)
+
+
+
+ org.jeecgframework.boot3
+ jeecg-boot-base-core
+
+
+
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslCustomerBizStatus.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslCustomerBizStatus.java
new file mode 100644
index 0000000..80eb49d
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslCustomerBizStatus.java
@@ -0,0 +1,24 @@
+package org.jeecg.modules.xslmes.constant;
+
+/**
+ * 客户业务状态(与「逻辑删除」无关)。删除仅由 del_flag 表示,一般不再写入 status。
+ *
+ * 字典 xslmes_customer_status:0=启用,1=停用,2=删除(可选)。
+ */
+public final class MesXslCustomerBizStatus {
+
+ private MesXslCustomerBizStatus() {}
+
+ /** 启用 */
+ public static final String ENABLED = "0";
+
+ /** 停用 */
+ public static final String DISABLED = "1";
+
+ /** 删除(字典项,业务上建议仅用 del_flag) */
+ public static final String DELETED = "2";
+
+ public static boolean isDisabled(String status) {
+ return DISABLED.equals(status);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslWarehouseCategory.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslWarehouseCategory.java
new file mode 100644
index 0000000..63bd508
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/constant/MesXslWarehouseCategory.java
@@ -0,0 +1,17 @@
+package org.jeecg.modules.xslmes.constant;
+
+/**
+ * MES 仓库分类(分类字典 sys_category,根编码 {@link #ROOT_CODE})
+ */
+public final class MesXslWarehouseCategory {
+
+ private MesXslWarehouseCategory() {}
+
+ /** 根节点编码,与 JCategorySelect 的 pcode 一致 */
+ public static final String ROOT_CODE = "XSLMES_WH";
+
+ /** 客户库(二楼):须关联客户 */
+ public static final String CUSTOMER_CATEGORY_CODE = "XSLMES_WH_F2_KH";
+ /** 供应商库(二楼):须关联供应商 */
+ public static final String SUPPLIER_CATEGORY_CODE = "XSLMES_WH_F2_GYS";
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslCustomerController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslCustomerController.java
new file mode 100644
index 0000000..afc3520
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslCustomerController.java
@@ -0,0 +1,154 @@
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus;
+import org.jeecg.modules.xslmes.entity.MesXslCustomer;
+import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * MES 客户管理
+ */
+@Tag(name = "MES客户管理")
+@RestController
+@RequestMapping("/xslmes/mesXslCustomer")
+@Slf4j
+public class MesXslCustomerController extends JeecgController {
+
+ @Autowired
+ private IMesXslCustomerService mesXslCustomerService;
+
+ @Operation(summary = "MES客户管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslCustomer mesXslCustomer,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslCustomer, req.getParameterMap());
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslCustomerService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES客户管理-添加")
+ @Operation(summary = "MES客户管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_customer:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslCustomer mesXslCustomer) {
+ // 新增默认启用(0);空白或未传时写入启用,并与 iz_enable 对齐
+ String st = mesXslCustomer.getStatus();
+ if (st != null) {
+ st = st.trim();
+ mesXslCustomer.setStatus(st.isEmpty() ? null : st);
+ }
+ if (mesXslCustomer.getStatus() == null || mesXslCustomer.getStatus().isEmpty()) {
+ mesXslCustomer.setStatus(MesXslCustomerBizStatus.ENABLED);
+ }
+ mesXslCustomerService.syncIzEnableWithStatus(mesXslCustomer);
+ mesXslCustomerService.save(mesXslCustomer);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES客户管理-编辑")
+ @Operation(summary = "MES客户管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_customer:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslCustomer mesXslCustomer) {
+ if (mesXslCustomer.getStatus() != null) {
+ String s = mesXslCustomer.getStatus().trim();
+ mesXslCustomer.setStatus(s.isEmpty() ? null : s);
+ }
+ mesXslCustomerService.syncIzEnableWithStatus(mesXslCustomer);
+ mesXslCustomerService.updateById(mesXslCustomer);
+ return Result.OK("编辑成功!");
+ }
+
+ @AutoLog(value = "MES客户管理-启用/停用")
+ @Operation(summary = "MES客户管理-启用/停用(字典 xslmes_customer_status:0启用 1停用)")
+ @RequiresPermissions("xslmes:mes_xsl_customer:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (status != null) {
+ status = status.trim();
+ }
+ if (!MesXslCustomerBizStatus.ENABLED.equals(status) && !MesXslCustomerBizStatus.DISABLED.equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ // 与 MesXslUnitController.updateStatus 一致用 lambdaUpdate;并同步 iz_enable(字典 1 停用时为 0)
+ int izEnable = MesXslCustomerBizStatus.DISABLED.equals(status) ? 0 : 1;
+ boolean updated = mesXslCustomerService.lambdaUpdate()
+ .eq(MesXslCustomer::getId, id)
+ .set(MesXslCustomer::getStatus, status)
+ .set(MesXslCustomer::getIzEnable, izEnable)
+ .update();
+ if (updated) {
+ return Result.OK("操作成功");
+ }
+ // MySQL 在 SET 值与库中完全一致时可能返回 0 行;或需二次确认是否已是目标状态
+ MesXslCustomer cur = mesXslCustomerService.getById(id);
+ if (cur != null && Objects.equals(status, cur.getStatus())) {
+ return Result.OK("操作成功");
+ }
+ return Result.error("操作失败,请确认记录存在且租户与当前登录一致(tenant_id 勿为空)");
+ }
+
+ @AutoLog(value = "MES客户管理-删除")
+ @Operation(summary = "MES客户管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_customer:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslCustomerService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES客户管理-批量删除")
+ @Operation(summary = "MES客户管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_customer:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslCustomerService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES客户管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslCustomer entity = mesXslCustomerService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_customer:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslCustomer mesXslCustomer) {
+ return super.exportXls(request, mesXslCustomer, MesXslCustomer.class, "MES客户管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_customer:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslCustomer.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslInstrumentController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslInstrumentController.java
new file mode 100644
index 0000000..8a54abe
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslInstrumentController.java
@@ -0,0 +1,126 @@
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.xslmes.entity.MesXslInstrument;
+import org.jeecg.modules.xslmes.service.IMesXslInstrumentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+
+/**
+ * MES 器具管理
+ */
+@Tag(name = "MES器具管理")
+@RestController
+@RequestMapping("/xslmes/mesXslInstrument")
+@Slf4j
+public class MesXslInstrumentController extends JeecgController {
+
+ @Autowired
+ private IMesXslInstrumentService mesXslInstrumentService;
+
+ @Operation(summary = "MES器具管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslInstrument mesXslInstrument,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslInstrument, req.getParameterMap());
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslInstrumentService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES器具管理-添加")
+ @Operation(summary = "MES器具管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_instrument:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslInstrument mesXslInstrument) {
+ if (mesXslInstrument.getStatus() == null || mesXslInstrument.getStatus().isEmpty()) {
+ mesXslInstrument.setStatus("0");
+ }
+ mesXslInstrumentService.save(mesXslInstrument);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES器具管理-编辑")
+ @Operation(summary = "MES器具管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_instrument:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslInstrument mesXslInstrument) {
+ mesXslInstrumentService.updateById(mesXslInstrument);
+ return Result.OK("编辑成功!");
+ }
+
+ @AutoLog(value = "MES器具管理-停用/启用")
+ @Operation(summary = "MES器具管理-停用/启用")
+ @RequiresPermissions("xslmes:mes_xsl_instrument:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (!"0".equals(status) && !"1".equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ boolean ok = mesXslInstrumentService.lambdaUpdate()
+ .eq(MesXslInstrument::getId, id)
+ .set(MesXslInstrument::getStatus, status)
+ .update();
+ return ok ? Result.OK("操作成功") : Result.error("操作失败");
+ }
+
+ @AutoLog(value = "MES器具管理-删除")
+ @Operation(summary = "MES器具管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_instrument:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslInstrumentService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES器具管理-批量删除")
+ @Operation(summary = "MES器具管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_instrument:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslInstrumentService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES器具管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslInstrument entity = mesXslInstrumentService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_instrument:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslInstrument mesXslInstrument) {
+ return super.exportXls(request, mesXslInstrument, MesXslInstrument.class, "MES器具管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_instrument:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslInstrument.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslSupplierController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslSupplierController.java
new file mode 100644
index 0000000..2e23f80
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslSupplierController.java
@@ -0,0 +1,126 @@
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.xslmes.entity.MesXslSupplier;
+import org.jeecg.modules.xslmes.service.IMesXslSupplierService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+
+/**
+ * MES 供应商管理
+ */
+@Tag(name = "MES供应商管理")
+@RestController
+@RequestMapping("/xslmes/mesXslSupplier")
+@Slf4j
+public class MesXslSupplierController extends JeecgController {
+
+ @Autowired
+ private IMesXslSupplierService mesXslSupplierService;
+
+ @Operation(summary = "MES供应商管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslSupplier mesXslSupplier,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslSupplier, req.getParameterMap());
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslSupplierService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES供应商管理-添加")
+ @Operation(summary = "MES供应商管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_supplier:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslSupplier mesXslSupplier) {
+ if (mesXslSupplier.getStatus() == null || mesXslSupplier.getStatus().isEmpty()) {
+ mesXslSupplier.setStatus("0");
+ }
+ mesXslSupplierService.save(mesXslSupplier);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES供应商管理-编辑")
+ @Operation(summary = "MES供应商管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_supplier:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslSupplier mesXslSupplier) {
+ mesXslSupplierService.updateById(mesXslSupplier);
+ return Result.OK("编辑成功!");
+ }
+
+ @AutoLog(value = "MES供应商管理-停用/启用")
+ @Operation(summary = "MES供应商管理-停用/启用")
+ @RequiresPermissions("xslmes:mes_xsl_supplier:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (!"0".equals(status) && !"1".equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ boolean ok = mesXslSupplierService.lambdaUpdate()
+ .eq(MesXslSupplier::getId, id)
+ .set(MesXslSupplier::getStatus, status)
+ .update();
+ return ok ? Result.OK("操作成功") : Result.error("操作失败");
+ }
+
+ @AutoLog(value = "MES供应商管理-删除")
+ @Operation(summary = "MES供应商管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_supplier:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslSupplierService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES供应商管理-批量删除")
+ @Operation(summary = "MES供应商管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_supplier:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslSupplierService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES供应商管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslSupplier entity = mesXslSupplierService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_supplier:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslSupplier mesXslSupplier) {
+ return super.exportXls(request, mesXslSupplier, MesXslSupplier.class, "MES供应商管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_supplier:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslSupplier.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslUnitController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslUnitController.java
new file mode 100644
index 0000000..f9bf937
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslUnitController.java
@@ -0,0 +1,133 @@
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.xslmes.entity.MesXslUnit;
+import org.jeecg.modules.xslmes.service.IMesXslUnitService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * MES 单位管理
+ */
+@Tag(name = "MES单位管理")
+@RestController
+@RequestMapping("/xslmes/mesXslUnit")
+@Slf4j
+public class MesXslUnitController extends JeecgController {
+
+ @Autowired
+ private IMesXslUnitService mesXslUnitService;
+
+ @Operation(summary = "MES单位管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslUnit mesXslUnit,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ @RequestParam(name = "treeCategoryId", required = false) String treeCategoryId,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslUnit, req.getParameterMap());
+ if (oConvertUtils.isNotEmpty(treeCategoryId)) {
+ List ids = mesXslUnitService.listDescendantCategoryIds(treeCategoryId);
+ queryWrapper.in("category_id", ids);
+ }
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslUnitService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES单位管理-添加")
+ @Operation(summary = "MES单位管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_unit:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslUnit mesXslUnit) {
+ if (mesXslUnit.getStatus() == null || mesXslUnit.getStatus().isEmpty()) {
+ mesXslUnit.setStatus("0");
+ }
+ mesXslUnitService.save(mesXslUnit);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES单位管理-编辑")
+ @Operation(summary = "MES单位管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_unit:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslUnit mesXslUnit) {
+ mesXslUnitService.updateById(mesXslUnit);
+ return Result.OK("编辑成功!");
+ }
+
+ @AutoLog(value = "MES单位管理-停用/启用")
+ @Operation(summary = "MES单位管理-停用/启用")
+ @RequiresPermissions("xslmes:mes_xsl_unit:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (!"0".equals(status) && !"1".equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ boolean ok = mesXslUnitService.lambdaUpdate()
+ .eq(MesXslUnit::getId, id)
+ .set(MesXslUnit::getStatus, status)
+ .update();
+ return ok ? Result.OK("操作成功") : Result.error("操作失败");
+ }
+
+ @AutoLog(value = "MES单位管理-删除")
+ @Operation(summary = "MES单位管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_unit:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslUnitService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES单位管理-批量删除")
+ @Operation(summary = "MES单位管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_unit:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslUnitService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES单位管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslUnit entity = mesXslUnitService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_unit:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslUnit mesXslUnit) {
+ return super.exportXls(request, mesXslUnit, MesXslUnit.class, "MES单位管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_unit:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslUnit.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslVehicleController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslVehicleController.java
new file mode 100644
index 0000000..99a2a62
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslVehicleController.java
@@ -0,0 +1,188 @@
+package org.jeecg.modules.xslmes.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.xslmes.entity.MesXslVehicle;
+import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+
+/**
+ * MES 车辆管理
+ */
+@Tag(name = "MES车辆管理")
+@RestController
+@RequestMapping("/xslmes/mesXslVehicle")
+@Slf4j
+public class MesXslVehicleController extends JeecgController {
+
+ @Autowired
+ private IMesXslVehicleService mesXslVehicleService;
+
+ @Operation(summary = "MES车辆管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslVehicle mesXslVehicle,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslVehicle, req.getParameterMap());
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslVehicleService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES车辆管理-添加")
+ @Operation(summary = "MES车辆管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslVehicle mesXslVehicle) {
+ if (oConvertUtils.isEmpty(mesXslVehicle.getVehicleBelong())) {
+ return Result.error("车辆归属不能为空");
+ }
+ if (mesXslVehicle.getStatus() == null || mesXslVehicle.getStatus().isEmpty()) {
+ mesXslVehicle.setStatus("0");
+ }
+ applyVehicleBelong(mesXslVehicle);
+ mesXslVehicleService.save(mesXslVehicle);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES车辆管理-编辑")
+ @Operation(summary = "MES车辆管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslVehicle mesXslVehicle) {
+ if (oConvertUtils.isEmpty(mesXslVehicle.getVehicleBelong())) {
+ return Result.error("车辆归属不能为空");
+ }
+ applyVehicleBelong(mesXslVehicle);
+ mesXslVehicleService.updateById(mesXslVehicle);
+ // updateById 默认不更新 null 字段,互斥侧需在库中显式置 NULL
+ forceNullOppositeFieldsInDb(mesXslVehicle.getId(), mesXslVehicle.getVehicleBelong());
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 按车辆归属清理互斥字段:客户/供应商/本公司
+ */
+ private void applyVehicleBelong(MesXslVehicle v) {
+ if (oConvertUtils.isEmpty(v.getVehicleBelong())) {
+ return;
+ }
+ String b = v.getVehicleBelong();
+ if ("1".equals(b)) {
+ v.setSupplierId(null);
+ v.setSupplierName(null);
+ v.setSupplierShortName(null);
+ } else if ("2".equals(b)) {
+ v.setCustomerIds(null);
+ v.setCustomerShortName(null);
+ } else if ("3".equals(b)) {
+ v.setCustomerIds(null);
+ v.setCustomerShortName(null);
+ v.setSupplierId(null);
+ v.setSupplierName(null);
+ v.setSupplierShortName(null);
+ }
+ }
+
+ /**
+ * 将互斥侧客户/供应商字段在数据库中置为 NULL(MyBatis-Plus updateById 会忽略 null)
+ */
+ private void forceNullOppositeFieldsInDb(String id, String vehicleBelong) {
+ if (oConvertUtils.isEmpty(id) || oConvertUtils.isEmpty(vehicleBelong)) {
+ return;
+ }
+ LambdaUpdateWrapper uw = new LambdaUpdateWrapper().eq(MesXslVehicle::getId, id);
+ if ("1".equals(vehicleBelong)) {
+ uw.set(MesXslVehicle::getSupplierId, null)
+ .set(MesXslVehicle::getSupplierName, null)
+ .set(MesXslVehicle::getSupplierShortName, null);
+ } else if ("2".equals(vehicleBelong)) {
+ uw.set(MesXslVehicle::getCustomerIds, null).set(MesXslVehicle::getCustomerShortName, null);
+ } else if ("3".equals(vehicleBelong)) {
+ uw.set(MesXslVehicle::getCustomerIds, null)
+ .set(MesXslVehicle::getCustomerShortName, null)
+ .set(MesXslVehicle::getSupplierId, null)
+ .set(MesXslVehicle::getSupplierName, null)
+ .set(MesXslVehicle::getSupplierShortName, null);
+ } else {
+ return;
+ }
+ mesXslVehicleService.update(null, uw);
+ }
+
+ @AutoLog(value = "MES车辆管理-停用/启用")
+ @Operation(summary = "MES车辆管理-停用/启用")
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (!"0".equals(status) && !"1".equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ boolean ok = mesXslVehicleService.lambdaUpdate()
+ .eq(MesXslVehicle::getId, id)
+ .set(MesXslVehicle::getStatus, status)
+ .update();
+ return ok ? Result.OK("操作成功") : Result.error("操作失败");
+ }
+
+ @AutoLog(value = "MES车辆管理-删除")
+ @Operation(summary = "MES车辆管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslVehicleService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES车辆管理-批量删除")
+ @Operation(summary = "MES车辆管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslVehicleService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES车辆管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslVehicle entity = mesXslVehicleService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslVehicle mesXslVehicle) {
+ return super.exportXls(request, mesXslVehicle, MesXslVehicle.class, "MES车辆管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_vehicle:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslVehicle.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslWarehouseController.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslWarehouseController.java
new file mode 100644
index 0000000..b92f09e
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/controller/MesXslWarehouseController.java
@@ -0,0 +1,131 @@
+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 jakarta.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
+import org.jeecg.modules.xslmes.service.IMesXslWarehouseService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import java.util.Arrays;
+
+/**
+ * MES 仓库管理
+ */
+@Tag(name = "MES仓库管理")
+@RestController
+@RequestMapping("/xslmes/mesXslWarehouse")
+@Slf4j
+public class MesXslWarehouseController extends JeecgController {
+
+ @Autowired
+ private IMesXslWarehouseService mesXslWarehouseService;
+
+ @Operation(summary = "MES仓库管理-分页列表查询")
+ @GetMapping(value = "/list")
+ public Result> queryPageList(
+ MesXslWarehouse mesXslWarehouse,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ @RequestParam(name = "treeCategoryId", required = false) String treeCategoryId,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(mesXslWarehouse, req.getParameterMap());
+ if (oConvertUtils.isNotEmpty(treeCategoryId)) {
+ queryWrapper.eq("warehouse_category", treeCategoryId);
+ }
+ Page page = new Page<>(pageNo, pageSize);
+ IPage pageList = mesXslWarehouseService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+ @AutoLog(value = "MES仓库管理-添加")
+ @Operation(summary = "MES仓库管理-添加")
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody MesXslWarehouse mesXslWarehouse) {
+ if (mesXslWarehouse.getStatus() == null || mesXslWarehouse.getStatus().isEmpty()) {
+ mesXslWarehouse.setStatus("0");
+ }
+ mesXslWarehouseService.save(mesXslWarehouse);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "MES仓库管理-编辑")
+ @Operation(summary = "MES仓库管理-编辑")
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:edit")
+ @RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
+ public Result edit(@RequestBody MesXslWarehouse mesXslWarehouse) {
+ mesXslWarehouseService.updateById(mesXslWarehouse);
+ return Result.OK("编辑成功!");
+ }
+
+ @AutoLog(value = "MES仓库管理-停用/启用")
+ @Operation(summary = "MES仓库管理-停用/启用(字典 xslmes_unit_status:0启用 1停用)")
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:updateStatus")
+ @PostMapping(value = "/updateStatus")
+ public Result updateStatus(
+ @RequestParam(name = "id", required = true) String id,
+ @RequestParam(name = "status", required = true) String status) {
+ if (!"0".equals(status) && !"1".equals(status)) {
+ return Result.error("状态参数非法");
+ }
+ boolean ok = mesXslWarehouseService.lambdaUpdate()
+ .eq(MesXslWarehouse::getId, id)
+ .set(MesXslWarehouse::getStatus, status)
+ .update();
+ return ok ? Result.OK("操作成功") : Result.error("操作失败");
+ }
+
+ @AutoLog(value = "MES仓库管理-删除")
+ @Operation(summary = "MES仓库管理-删除")
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ mesXslWarehouseService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+ @AutoLog(value = "MES仓库管理-批量删除")
+ @Operation(summary = "MES仓库管理-批量删除")
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ mesXslWarehouseService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+ @Operation(summary = "MES仓库管理-通过id查询")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ MesXslWarehouse entity = mesXslWarehouseService.getById(id);
+ if (entity == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(entity);
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:exportXls")
+ @RequestMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, MesXslWarehouse mesXslWarehouse) {
+ return super.exportXls(request, mesXslWarehouse, MesXslWarehouse.class, "MES仓库管理");
+ }
+
+ @RequiresPermissions("xslmes:mes_xsl_warehouse:importExcel")
+ @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, MesXslWarehouse.class);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslCustomer.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslCustomer.java
new file mode 100644
index 0000000..a698b00
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslCustomer.java
@@ -0,0 +1,69 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+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.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+
+/**
+ * MES 客户管理
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_customer")
+@Schema(description = "MES客户管理")
+public class MesXslCustomer extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "客户编码", width = 20)
+ @Schema(description = "客户编码")
+ private String customerCode;
+
+ @Excel(name = "客户名称", width = 28)
+ @Schema(description = "客户名称")
+ private String customerName;
+
+ @Excel(name = "客户简称", width = 18)
+ @Schema(description = "客户简称")
+ private String customerShortName;
+
+ @Excel(name = "客户区域", width = 15, dicCode = "xslmes_customer_region")
+ @Dict(dicCode = "xslmes_customer_region")
+ @Schema(description = "客户区域")
+ private String customerRegion;
+
+ @Excel(name = "ERP编码", width = 18)
+ @Schema(description = "ERP编码")
+ private String erpCode;
+
+ @Excel(name = "状态", width = 12, dicCode = "xslmes_customer_status")
+ @Dict(dicCode = "xslmes_customer_status")
+ @Schema(description = "业务状态(字典 xslmes_customer_status:0启用1停用2删除);逻辑删除见 del_flag")
+ private String status;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Excel(name = "客户描述", width = 36)
+ @Schema(description = "客户描述")
+ private String customerDesc;
+
+ @Excel(name = "是否启用", width = 10)
+ @Schema(description = "是否启用:停用(status=1) 为 0,否则为 1(由服务端同步)")
+ private Integer izEnable;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslInstrument.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslInstrument.java
new file mode 100644
index 0000000..70d5c62
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslInstrument.java
@@ -0,0 +1,51 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+
+/**
+ * MES 器具管理
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_instrument")
+@Schema(description = "MES器具管理")
+public class MesXslInstrument extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "编号条码", width = 22)
+ @Schema(description = "编号/条码")
+ private String barcode;
+
+ @Excel(name = "状态", width = 10, dicCode = "xslmes_instrument_status")
+ @Dict(dicCode = "xslmes_instrument_status")
+ @Schema(description = "状态:0启用 1停用")
+ private String status;
+
+ @Excel(name = "规格型号", width = 18, dicCode = "xslmes_instrument_spec")
+ @Dict(dicCode = "xslmes_instrument_spec")
+ @Schema(description = "规格型号")
+ private String specModel;
+
+ @Excel(name = "备注", width = 28)
+ @Schema(description = "备注")
+ private String remark;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslSupplier.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslSupplier.java
new file mode 100644
index 0000000..7f9f95e
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslSupplier.java
@@ -0,0 +1,58 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+
+/**
+ * MES 供应商管理
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_supplier")
+@Schema(description = "MES供应商管理")
+public class MesXslSupplier extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "编码", width = 18)
+ @Schema(description = "编码")
+ private String supplierCode;
+
+ @Excel(name = "名称", width = 24)
+ @Schema(description = "名称")
+ private String supplierName;
+
+ @Excel(name = "简称", width = 16)
+ @Schema(description = "简称")
+ private String supplierShortName;
+
+ @Excel(name = "ERP编码", width = 18)
+ @Schema(description = "ERP编码")
+ private String erpCode;
+
+ @Excel(name = "备注", width = 28)
+ @Schema(description = "备注")
+ private String remark;
+
+ @Excel(name = "状态", width = 10, dicCode = "xslmes_supplier_status")
+ @Dict(dicCode = "xslmes_supplier_status")
+ @Schema(description = "状态:0启用 1停用")
+ private String status;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslUnit.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslUnit.java
new file mode 100644
index 0000000..154bb83
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslUnit.java
@@ -0,0 +1,59 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+
+/**
+ * MES 单位
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_unit")
+@Schema(description = "MES单位")
+public class MesXslUnit extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "编码", width = 18)
+ @Schema(description = "编码")
+ private String unitCode;
+
+ @Excel(name = "名称", width = 20)
+ @Schema(description = "名称")
+ private String unitName;
+
+ @Excel(name = "ERP编码", width = 18)
+ @Schema(description = "ERP编码")
+ private String erpCode;
+
+ @Excel(name = "所属分类", width = 20, dictTable = "sys_category", dicText = "name", dicCode = "id")
+ @Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")
+ @Schema(description = "所属分类(sys_category.id,根编码 XSLMES_UNIT)")
+ private String categoryId;
+
+ @Excel(name = "描述", width = 40)
+ @Schema(description = "描述")
+ private String unitDesc;
+
+ @Excel(name = "状态", width = 10, dicCode = "xslmes_unit_status")
+ @Dict(dicCode = "xslmes_unit_status")
+ @Schema(description = "状态:0启用 1停用")
+ private String status;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslVehicle.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslVehicle.java
new file mode 100644
index 0000000..86f33d4
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslVehicle.java
@@ -0,0 +1,104 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * MES 车辆管理
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_vehicle")
+@Schema(description = "MES车辆管理")
+public class MesXslVehicle extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "车牌号", width = 18)
+ @Schema(description = "车牌号")
+ private String plateNumber;
+
+ @Excel(name = "车辆归属", width = 12, dicCode = "xslmes_vehicle_belong")
+ @Dict(dicCode = "xslmes_vehicle_belong")
+ @Schema(description = "车辆归属:1客户 2供应商 3本公司")
+ private String vehicleBelong;
+
+ @Excel(name = "车辆皮重KG", width = 14)
+ @Schema(description = "车辆皮重(KG)")
+ private BigDecimal tareWeightKg;
+
+ @Excel(name = "装载量", width = 14)
+ @Schema(description = "装载量")
+ private BigDecimal loadCapacity;
+
+ @Excel(name = "单位ID", width = 22)
+ @Schema(description = "单位ID(mes_xsl_unit.id)")
+ private String unitId;
+
+ @Excel(name = "单位", width = 10)
+ @Schema(description = "单位(名称,与所选单位一致)")
+ private String loadUnit;
+
+ @Excel(name = "客户ID", width = 36)
+ @Schema(description = "客户ID,多选逗号分隔")
+ private String customerIds;
+
+ @Excel(name = "客户简称", width = 28)
+ @Schema(description = "客户简称展示")
+ private String customerShortName;
+
+ @Excel(name = "供应商ID", width = 22)
+ @Schema(description = "供应商ID")
+ private String supplierId;
+
+ @Excel(name = "供应商名称", width = 24)
+ @Schema(description = "供应商名称")
+ private String supplierName;
+
+ @Excel(name = "供应商简称", width = 18)
+ @Schema(description = "供应商简称")
+ private String supplierShortName;
+
+ @Excel(name = "车长", width = 12)
+ @Schema(description = "车长")
+ private BigDecimal vehicleLength;
+
+ @Excel(name = "车宽", width = 12)
+ @Schema(description = "车宽")
+ private BigDecimal vehicleWidth;
+
+ @Excel(name = "车高", width = 12)
+ @Schema(description = "车高")
+ private BigDecimal vehicleHeight;
+
+ @Excel(name = "司机", width = 14)
+ @Schema(description = "司机")
+ private String driverName;
+
+ @Excel(name = "联系电话", width = 16)
+ @Schema(description = "联系电话")
+ private String driverPhone;
+
+ @Excel(name = "状态", width = 10, dicCode = "xslmes_vehicle_status")
+ @Dict(dicCode = "xslmes_vehicle_status")
+ @Schema(description = "状态:0启用 1停用")
+ private String status;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslWarehouse.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslWarehouse.java
new file mode 100644
index 0000000..66d24e6
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/entity/MesXslWarehouse.java
@@ -0,0 +1,69 @@
+package org.jeecg.modules.xslmes.entity;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.jeecg.common.system.base.entity.JeecgEntity;
+import org.jeecgframework.poi.excel.annotation.Excel;
+
+import java.io.Serializable;
+
+/**
+ * MES 仓库管理
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+@TableName("mes_xsl_warehouse")
+@Schema(description = "MES仓库管理")
+public class MesXslWarehouse extends JeecgEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Excel(name = "仓库编码", width = 18)
+ @Schema(description = "仓库编码")
+ private String warehouseCode;
+
+ @Excel(name = "仓库名称", width = 22)
+ @Schema(description = "仓库名称")
+ private String warehouseName;
+
+ @Excel(name = "仓库分类", width = 14, dictTable = "sys_category", dicText = "name", dicCode = "id")
+ @Dict(dictTable = "sys_category", dicText = "name", dicCode = "id")
+ @Schema(description = "仓库分类(sys_category.id,根编码 XSLMES_WH)")
+ private String warehouseCategory;
+
+ @Excel(name = "ERP编码", width = 18)
+ @Schema(description = "ERP编码")
+ private String erpCode;
+
+ @Excel(name = "状态", width = 10, dicCode = "xslmes_unit_status")
+ @Dict(dicCode = "xslmes_unit_status")
+ @Schema(description = "状态:0启用 1停用")
+ private String status;
+
+ @Schema(description = "客户ID")
+ private String customerId;
+
+ @Excel(name = "客户简称", width = 16)
+ @Schema(description = "客户简称")
+ private String customerShortName;
+
+ @Schema(description = "供应商ID")
+ private String supplierId;
+
+ @Excel(name = "供应商简称", width = 14)
+ @Schema(description = "供应商简称")
+ private String supplierShortName;
+
+ @Schema(description = "删除状态(0正常 1已删除)")
+ @TableLogic
+ private Integer delFlag;
+
+ @Schema(description = "租户ID")
+ private Integer tenantId;
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslCustomerMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslCustomerMapper.java
new file mode 100644
index 0000000..0851426
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslCustomerMapper.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.xslmes.entity.MesXslCustomer;
+
+/**
+ * MES 客户管理 Mapper
+ */
+@Mapper
+public interface MesXslCustomerMapper extends BaseMapper {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslInstrumentMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslInstrumentMapper.java
new file mode 100644
index 0000000..d58737a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslInstrumentMapper.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.xslmes.entity.MesXslInstrument;
+
+/**
+ * MES 器具管理 Mapper
+ */
+@Mapper
+public interface MesXslInstrumentMapper extends BaseMapper {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslSupplierMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslSupplierMapper.java
new file mode 100644
index 0000000..f9afe11
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslSupplierMapper.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.xslmes.entity.MesXslSupplier;
+
+/**
+ * MES 供应商管理 Mapper
+ */
+@Mapper
+public interface MesXslSupplierMapper extends BaseMapper {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslUnitMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslUnitMapper.java
new file mode 100644
index 0000000..fd98852
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslUnitMapper.java
@@ -0,0 +1,24 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.jeecg.modules.xslmes.entity.MesXslUnit;
+
+import java.util.List;
+
+/**
+ * MES 单位 Mapper
+ */
+@Mapper
+public interface MesXslUnitMapper extends BaseMapper {
+
+ /** 分类字典子树:含自身及所有后代 id(MySQL 8 递归 CTE) */
+ @Select("WITH RECURSIVE unit_cat_tree AS ( "
+ + " SELECT id FROM sys_category WHERE id = #{rootId} "
+ + " UNION ALL "
+ + " SELECT c.id FROM sys_category c INNER JOIN unit_cat_tree t ON c.pid = t.id "
+ + ") SELECT id FROM unit_cat_tree")
+ List listDescendantCategoryIds(@Param("rootId") String rootId);
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslVehicleMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslVehicleMapper.java
new file mode 100644
index 0000000..b8219eb
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslVehicleMapper.java
@@ -0,0 +1,12 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.xslmes.entity.MesXslVehicle;
+
+/**
+ * MES 车辆管理 Mapper
+ */
+@Mapper
+public interface MesXslVehicleMapper extends BaseMapper {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslWarehouseMapper.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslWarehouseMapper.java
new file mode 100644
index 0000000..3969f89
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/MesXslWarehouseMapper.java
@@ -0,0 +1,18 @@
+package org.jeecg.modules.xslmes.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
+
+/**
+ * MES 仓库管理 Mapper
+ */
+@Mapper
+public interface MesXslWarehouseMapper extends BaseMapper {
+
+ /** 按分类字典主键取编码(用于客户库/供应商库等业务判断) */
+ @Select("SELECT code FROM sys_category WHERE id = #{id}")
+ String queryCategoryCodeById(@Param("id") String id);
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslCustomerMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslCustomerMapper.xml
new file mode 100644
index 0000000..c683610
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslCustomerMapper.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslSupplierMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslSupplierMapper.xml
new file mode 100644
index 0000000..fab0957
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslSupplierMapper.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslUnitMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslUnitMapper.xml
new file mode 100644
index 0000000..609a474
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslUnitMapper.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslVehicleMapper.xml b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslVehicleMapper.xml
new file mode 100644
index 0000000..78c3074
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/mapper/xml/MesXslVehicleMapper.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/package-info.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/package-info.java
new file mode 100644
index 0000000..2634380
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * MES XSL 业务模块(Maven 工程名:jeecg-module-xslmes)。
+ * 包含:客户管理({@link org.jeecg.modules.xslmes.entity.MesXslCustomer})等。
+ */
+package org.jeecg.modules.xslmes;
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslCustomerService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslCustomerService.java
new file mode 100644
index 0000000..ee17e54
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslCustomerService.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslCustomer;
+
+/**
+ * MES 客户管理
+ */
+public interface IMesXslCustomerService extends IService {
+
+ /**
+ * 按业务状态同步 izEnable:停用(字典值 1)为 0,其余为 1。删除仅 del_flag,与 status 无关。
+ */
+ void syncIzEnableWithStatus(MesXslCustomer entity);
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslInstrumentService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslInstrumentService.java
new file mode 100644
index 0000000..98d7f02
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslInstrumentService.java
@@ -0,0 +1,10 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslInstrument;
+
+/**
+ * MES 器具管理
+ */
+public interface IMesXslInstrumentService extends IService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslSupplierService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslSupplierService.java
new file mode 100644
index 0000000..3cd3b5d
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslSupplierService.java
@@ -0,0 +1,10 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslSupplier;
+
+/**
+ * MES 供应商管理
+ */
+public interface IMesXslSupplierService extends IService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslUnitService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslUnitService.java
new file mode 100644
index 0000000..5e406e6
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslUnitService.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslUnit;
+
+import java.util.List;
+
+/**
+ * MES 单位
+ */
+public interface IMesXslUnitService extends IService {
+
+ /** 单位分类(sys_category)选中节点及其所有下级 id,用于列表筛选 */
+ List listDescendantCategoryIds(String rootId);
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslVehicleService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslVehicleService.java
new file mode 100644
index 0000000..3cf611a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslVehicleService.java
@@ -0,0 +1,10 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslVehicle;
+
+/**
+ * MES 车辆管理
+ */
+public interface IMesXslVehicleService extends IService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslWarehouseService.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslWarehouseService.java
new file mode 100644
index 0000000..5ccb5f0
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/IMesXslWarehouseService.java
@@ -0,0 +1,10 @@
+package org.jeecg.modules.xslmes.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
+
+/**
+ * MES 仓库管理
+ */
+public interface IMesXslWarehouseService extends IService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslCustomerServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslCustomerServiceImpl.java
new file mode 100644
index 0000000..9462b76
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslCustomerServiceImpl.java
@@ -0,0 +1,32 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus;
+import org.jeecg.modules.xslmes.entity.MesXslCustomer;
+import org.jeecg.modules.xslmes.mapper.MesXslCustomerMapper;
+import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
+import org.springframework.stereotype.Service;
+
+/**
+ * MES 客户管理
+ */
+@Service
+public class MesXslCustomerServiceImpl extends ServiceImpl implements IMesXslCustomerService {
+
+ @Override
+ public void syncIzEnableWithStatus(MesXslCustomer entity) {
+ if (entity == null) {
+ return;
+ }
+ String s = entity.getStatus();
+ if (s != null) {
+ s = s.trim();
+ }
+ // 仅停用(字典值1) 为未启用,其余字典值视为启用
+ if (MesXslCustomerBizStatus.isDisabled(s)) {
+ entity.setIzEnable(0);
+ } else {
+ entity.setIzEnable(1);
+ }
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslInstrumentServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslInstrumentServiceImpl.java
new file mode 100644
index 0000000..f47f5e3
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslInstrumentServiceImpl.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.xslmes.entity.MesXslInstrument;
+import org.jeecg.modules.xslmes.mapper.MesXslInstrumentMapper;
+import org.jeecg.modules.xslmes.service.IMesXslInstrumentService;
+import org.springframework.stereotype.Service;
+
+/**
+ * MES 器具管理
+ */
+@Service
+public class MesXslInstrumentServiceImpl extends ServiceImpl implements IMesXslInstrumentService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslSupplierServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslSupplierServiceImpl.java
new file mode 100644
index 0000000..ec7bd60
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslSupplierServiceImpl.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.xslmes.entity.MesXslSupplier;
+import org.jeecg.modules.xslmes.mapper.MesXslSupplierMapper;
+import org.jeecg.modules.xslmes.service.IMesXslSupplierService;
+import org.springframework.stereotype.Service;
+
+/**
+ * MES 供应商管理
+ */
+@Service
+public class MesXslSupplierServiceImpl extends ServiceImpl implements IMesXslSupplierService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslUnitServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslUnitServiceImpl.java
new file mode 100644
index 0000000..be5c463
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslUnitServiceImpl.java
@@ -0,0 +1,21 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.xslmes.entity.MesXslUnit;
+import org.jeecg.modules.xslmes.mapper.MesXslUnitMapper;
+import org.jeecg.modules.xslmes.service.IMesXslUnitService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * MES 单位
+ */
+@Service
+public class MesXslUnitServiceImpl extends ServiceImpl implements IMesXslUnitService {
+
+ @Override
+ public List listDescendantCategoryIds(String rootId) {
+ return baseMapper.listDescendantCategoryIds(rootId);
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslVehicleServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslVehicleServiceImpl.java
new file mode 100644
index 0000000..23ab5ec
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslVehicleServiceImpl.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.xslmes.entity.MesXslVehicle;
+import org.jeecg.modules.xslmes.mapper.MesXslVehicleMapper;
+import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
+import org.springframework.stereotype.Service;
+
+/**
+ * MES 车辆管理
+ */
+@Service
+public class MesXslVehicleServiceImpl extends ServiceImpl implements IMesXslVehicleService {
+}
diff --git a/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslWarehouseServiceImpl.java b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslWarehouseServiceImpl.java
new file mode 100644
index 0000000..3333a35
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module/jeecg-module-xslmes/src/main/java/org/jeecg/modules/xslmes/service/impl/MesXslWarehouseServiceImpl.java
@@ -0,0 +1,69 @@
+package org.jeecg.modules.xslmes.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.exception.JeecgBootException;
+import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.modules.xslmes.constant.MesXslWarehouseCategory;
+import org.jeecg.modules.xslmes.entity.MesXslWarehouse;
+import org.jeecg.modules.xslmes.mapper.MesXslWarehouseMapper;
+import org.jeecg.modules.xslmes.service.IMesXslWarehouseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * MES 仓库管理
+ */
+@Service
+public class MesXslWarehouseServiceImpl extends ServiceImpl implements IMesXslWarehouseService {
+
+ @Override
+ public boolean save(MesXslWarehouse entity) {
+ normalizePartners(entity);
+ validatePartners(entity);
+ return super.save(entity);
+ }
+
+ @Override
+ public boolean updateById(MesXslWarehouse entity) {
+ normalizePartners(entity);
+ validatePartners(entity);
+ return super.updateById(entity);
+ }
+
+ /**
+ * 非客户库清空客户;非供应商库清空供应商(切换分类时避免脏数据)
+ */
+ private void normalizePartners(MesXslWarehouse e) {
+ if (oConvertUtils.isEmpty(e.getWarehouseCategory())) {
+ e.setCustomerId(null);
+ e.setCustomerShortName(null);
+ e.setSupplierId(null);
+ e.setSupplierShortName(null);
+ return;
+ }
+ String code = baseMapper.queryCategoryCodeById(e.getWarehouseCategory());
+ if (!MesXslWarehouseCategory.CUSTOMER_CATEGORY_CODE.equals(code)) {
+ e.setCustomerId(null);
+ e.setCustomerShortName(null);
+ }
+ if (!MesXslWarehouseCategory.SUPPLIER_CATEGORY_CODE.equals(code)) {
+ e.setSupplierId(null);
+ e.setSupplierShortName(null);
+ }
+ }
+
+ private void validatePartners(MesXslWarehouse e) {
+ if (oConvertUtils.isEmpty(e.getWarehouseCategory())) {
+ return;
+ }
+ String code = baseMapper.queryCategoryCodeById(e.getWarehouseCategory());
+ if (MesXslWarehouseCategory.CUSTOMER_CATEGORY_CODE.equals(code)) {
+ if (oConvertUtils.isEmpty(e.getCustomerId())) {
+ throw new JeecgBootException("仓库分类为客户库时,请选择客户");
+ }
+ } else if (MesXslWarehouseCategory.SUPPLIER_CATEGORY_CODE.equals(code)) {
+ if (oConvertUtils.isEmpty(e.getSupplierId())) {
+ throw new JeecgBootException("仓库分类为供应商库时,请选择供应商");
+ }
+ }
+ }
+}
diff --git a/jeecg-boot/jeecg-boot-module/pom.xml b/jeecg-boot/jeecg-boot-module/pom.xml
index ee6e528..7dd9945 100644
--- a/jeecg-boot/jeecg-boot-module/pom.xml
+++ b/jeecg-boot/jeecg-boot-module/pom.xml
@@ -16,6 +16,7 @@
jeecg-module-demo
jeecg-boot-module-airag
jeecg-module-print
+ jeecg-module-xslmes
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/config/application-liteflow.yml b/jeecg-boot/jeecg-module-system/jeecg-system-start/config/application-liteflow.yml
new file mode 100644
index 0000000..e1a7c18
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/config/application-liteflow.yml
@@ -0,0 +1,47 @@
+liteflow:
+ print-banner: false
+ parse-mode: PARSE_ONE_ON_FIRST_EXEC
+ #异步线程最长的等待时间秒(只用于when),默认值为15
+# when-max-wait-seconds: 180
+ rule-source-ext-data-map:
+# url: jdbc:mysql://localhost:3306/poseidon
+# driverClassName: com.mysql.cj.jdbc.Driver
+# username: root
+# password: 123456
+ applicationName: jeecg
+ #是否开启SQL日志
+ sqlLogEnabled: true
+ #是否开启SQL数据轮询自动刷新机制 默认不开启
+# pollingEnabled: false
+ #SQL数据轮询时间间隔(s) 默认为60s
+# pollingIntervalSeconds: 60
+ #规则配置后首次轮询的起始时间(s) 默认为60s
+# pollingStartSeconds: 60
+ #以下是chain表的配置,这个一定得有
+ #编排规则表的表名
+ chainTableName: airag_flow
+ #编排规则表中应用名称存储字段名
+ chainApplicationNameField: application_name
+ #规则名称存储的字段名
+ chainNameField: id
+ #EL表达式的字段(只存EL)
+ elDataField: chain
+ #以下是决策路由字段的配置,如果你没用到决策路由,可以不配置
+# routeField: route
+# namespaceField: namespace
+# #是否启用这条规则
+# chainEnableField: enable
+# #规则表自定义过滤SQL
+ chainCustomSql: select id, application_name, chain from airag_flow where status = 'enable' and chain is not null
+ #以下是script表的配置,如果你没使用到脚本,下面可以不配置
+# scriptTableName: script
+# scriptApplicationNameField: application_name
+# scriptIdField: script_id
+# scriptNameField: script_name
+# scriptDataField: script_data
+# scriptTypeField: script_type
+# scriptLanguageField: script_language
+# #是否启用这条脚本
+# scriptEnableField: enable
+# #脚本表自定义过滤SQL
+# scriptCustomSql: 这里设置自定义脚本表SQL
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/cp.txt b/jeecg-boot/jeecg-module-system/jeecg-system-start/cp.txt
new file mode 100644
index 0000000..35a4718
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/cp.txt
@@ -0,0 +1 @@
+F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-system-biz\3.9.1\jeecg-system-biz-3.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-system-local-api\3.9.1\jeecg-system-local-api-3.9.1.jar;F:\maven-3.6.3-z\repository\org\hibernate\hibernate-core\5.6.7.Final\hibernate-core-5.6.7.Final.jar;F:\maven-3.6.3-z\repository\org\jboss\logging\jboss-logging\3.6.1.Final\jboss-logging-3.6.1.Final.jar;F:\maven-3.6.3-z\repository\javax\persistence\javax.persistence-api\2.2\javax.persistence-api-2.2.jar;F:\maven-3.6.3-z\repository\net\bytebuddy\byte-buddy\1.17.7\byte-buddy-1.17.7.jar;F:\maven-3.6.3-z\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;F:\maven-3.6.3-z\repository\org\jboss\spec\javax\transaction\jboss-transaction-api_1.2_spec\1.1.1.Final\jboss-transaction-api_1.2_spec-1.1.1.Final.jar;F:\maven-3.6.3-z\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;F:\maven-3.6.3-z\repository\com\fasterxml\classmate\1.7.0\classmate-1.7.0.jar;F:\maven-3.6.3-z\repository\javax\activation\javax.activation-api\1.2.0\javax.activation-api-1.2.0.jar;F:\maven-3.6.3-z\repository\org\hibernate\common\hibernate-commons-annotations\5.1.2.Final\hibernate-commons-annotations-5.1.2.Final.jar;F:\maven-3.6.3-z\repository\javax\xml\bind\jaxb-api\2.3.1\jaxb-api-2.3.1.jar;F:\maven-3.6.3-z\repository\org\glassfish\jaxb\jaxb-runtime\2.3.3\jaxb-runtime-2.3.3.jar;F:\maven-3.6.3-z\repository\org\glassfish\jaxb\txw2\4.0.5\txw2-4.0.5.jar;F:\maven-3.6.3-z\repository\com\sun\istack\istack-commons-runtime\4.1.2\istack-commons-runtime-4.1.2.jar;F:\maven-3.6.3-z\repository\com\sun\activation\jakarta.activation\1.2.2\jakarta.activation-1.2.2.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\hibernate-re\3.9.1-beta\hibernate-re-3.9.1-beta.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-boot-module-airag\3.9.1\jeecg-boot-module-airag-3.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-aiflow\3.9.1-beta1\jeecg-aiflow-3.9.1-beta1.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-spring-boot-starter\2.15.0\liteflow-spring-boot-starter-2.15.0.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-spring\2.15.0\liteflow-spring-2.15.0.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-core\2.15.0\liteflow-core-2.15.0.jar;F:\maven-3.6.3-z\repository\org\dom4j\dom4j\2.1.4\dom4j-2.1.4.jar;F:\maven-3.6.3-z\repository\com\alibaba\transmittable-thread-local\2.14.5\transmittable-thread-local-2.14.5.jar;F:\maven-3.6.3-z\repository\com\alibaba\QLExpress\3.3.4\QLExpress-3.3.4.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-text\1.14.0\commons-text-1.14.0.jar;F:\maven-3.6.3-z\repository\com\github\ben-manes\caffeine\caffeine\3.2.2\caffeine-3.2.2.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-rule-sql\2.15.0\liteflow-rule-sql-2.15.0.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-script-graaljs\2.15.0\liteflow-script-graaljs-2.15.0.jar;F:\maven-3.6.3-z\repository\org\graalvm\js\js\22.0.0\js-22.0.0.jar;F:\maven-3.6.3-z\repository\org\graalvm\regex\regex\22.0.0\regex-22.0.0.jar;F:\maven-3.6.3-z\repository\org\graalvm\truffle\truffle-api\22.0.0\truffle-api-22.0.0.jar;F:\maven-3.6.3-z\repository\org\graalvm\sdk\graal-sdk\22.0.0\graal-sdk-22.0.0.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-script-groovy\2.15.0\liteflow-script-groovy-2.15.0.jar;F:\maven-3.6.3-z\repository\org\codehaus\groovy\groovy-jsr223\3.0.25\groovy-jsr223-3.0.25.jar;F:\maven-3.6.3-z\repository\org\codehaus\groovy\groovy\3.0.25\groovy-3.0.25.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-script-python\2.15.0\liteflow-script-python-2.15.0.jar;F:\maven-3.6.3-z\repository\org\python\jython-standalone\2.7.4\jython-standalone-2.7.4.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-script-kotlin\2.15.0\liteflow-script-kotlin-2.15.0.jar;F:\maven-3.6.3-z\repository\com\yomahub\liteflow-script-aviator\2.15.0\liteflow-script-aviator-2.15.0.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-open-ai\1.9.1\langchain4j-open-ai-1.9.1.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-core\1.9.1\langchain4j-core-1.9.1.jar;F:\maven-3.6.3-z\repository\org\jspecify\jspecify\1.0.0\jspecify-1.0.0.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-http-client\1.9.1\langchain4j-http-client-1.9.1.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-http-client-jdk\1.9.1\langchain4j-http-client-jdk-1.9.1.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\core\jackson-annotations\2.19.2\jackson-annotations-2.19.2.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\core\jackson-core\2.19.2\jackson-core-2.19.2.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\core\jackson-databind\2.19.2\jackson-databind-2.19.2.jar;F:\maven-3.6.3-z\repository\com\knuddels\jtokkit\1.1.0\jtokkit-1.1.0.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-mcp\1.9.1-beta17\langchain4j-mcp-1.9.1-beta17.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j\1.9.1\langchain4j-1.9.1.jar;F:\maven-3.6.3-z\repository\org\apache\opennlp\opennlp-tools\2.5.4\opennlp-tools-2.5.4.jar;F:\maven-3.6.3-z\repository\com\squareup\okhttp3\okhttp-sse\4.12.0\okhttp-sse-4.12.0.jar;F:\maven-3.6.3-z\repository\org\jetbrains\kotlin\kotlin-stdlib-jdk8\1.9.25\kotlin-stdlib-jdk8-1.9.25.jar;F:\maven-3.6.3-z\repository\org\jetbrains\kotlin\kotlin-stdlib-jdk7\1.9.25\kotlin-stdlib-jdk7-1.9.25.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-ollama\1.9.1\langchain4j-ollama-1.9.1.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-community-zhipu-ai\1.9.1-beta17\langchain4j-community-zhipu-ai-1.9.1-beta17.jar;F:\maven-3.6.3-z\repository\io\jsonwebtoken\jjwt\0.13.0\jjwt-0.13.0.jar;F:\maven-3.6.3-z\repository\io\jsonwebtoken\jjwt-api\0.13.0\jjwt-api-0.13.0.jar;F:\maven-3.6.3-z\repository\io\jsonwebtoken\jjwt-impl\0.13.0\jjwt-impl-0.13.0.jar;F:\maven-3.6.3-z\repository\io\jsonwebtoken\jjwt-jackson\0.13.0\jjwt-jackson-0.13.0.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-community-qianfan\1.9.1-beta17\langchain4j-community-qianfan-1.9.1-beta17.jar;F:\maven-3.6.3-z\repository\com\squareup\retrofit2\retrofit\2.9.0\retrofit-2.9.0.jar;F:\maven-3.6.3-z\repository\com\squareup\retrofit2\converter-jackson\2.9.0\converter-jackson-2.9.0.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-community-dashscope\1.9.1-beta17\langchain4j-community-dashscope-1.9.1-beta17.jar;F:\maven-3.6.3-z\repository\com\alibaba\dashscope-sdk-java\2.22.2\dashscope-sdk-java-2.22.2.jar;F:\maven-3.6.3-z\repository\io\reactivex\rxjava2\rxjava\2.2.21\rxjava-2.2.21.jar;F:\maven-3.6.3-z\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;F:\maven-3.6.3-z\repository\com\squareup\okhttp3\logging-interceptor\4.12.0\logging-interceptor-4.12.0.jar;F:\maven-3.6.3-z\repository\com\github\victools\jsonschema-generator\4.31.1\jsonschema-generator-4.31.1.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-anthropic\1.9.1\langchain4j-anthropic-1.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\langchain4j-pgvector\1.3.0-beta9\langchain4j-pgvector-1.3.0-beta9.jar;F:\maven-3.6.3-z\repository\com\pgvector\pgvector\0.1.6\pgvector-0.1.6.jar;F:\maven-3.6.3-z\repository\dev\langchain4j\langchain4j-document-parser-apache-poi\1.9.1-beta17\langchain4j-document-parser-apache-poi-1.9.1-beta17.jar;F:\maven-3.6.3-z\repository\org\apache\poi\poi\5.4.0\poi-5.4.0.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-math3\3.6.1\commons-math3-3.6.1.jar;F:\maven-3.6.3-z\repository\com\zaxxer\SparseBitSet\1.3\SparseBitSet-1.3.jar;F:\maven-3.6.3-z\repository\org\apache\logging\log4j\log4j-api\2.24.3\log4j-api-2.24.3.jar;F:\maven-3.6.3-z\repository\org\apache\poi\poi-ooxml\5.4.0\poi-ooxml-5.4.0.jar;F:\maven-3.6.3-z\repository\org\apache\poi\poi-ooxml-lite\5.4.0\poi-ooxml-lite-5.4.0.jar;F:\maven-3.6.3-z\repository\org\apache\xmlbeans\xmlbeans\5.3.0\xmlbeans-5.3.0.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-compress\1.27.1\commons-compress-1.27.1.jar;F:\maven-3.6.3-z\repository\com\github\virtuald\curvesapi\1.08\curvesapi-1.08.jar;F:\maven-3.6.3-z\repository\org\apache\poi\poi-scratchpad\5.4.0\poi-scratchpad-5.4.0.jar;F:\maven-3.6.3-z\repository\org\apache\tika\tika-core\3.2.3\tika-core-3.2.3.jar;F:\maven-3.6.3-z\repository\org\apache\tika\tika-parser-html-module\3.2.3\tika-parser-html-module-3.2.3.jar;F:\maven-3.6.3-z\repository\org\jsoup\jsoup\1.21.2\jsoup-1.21.2.jar;F:\maven-3.6.3-z\repository\org\apache\tika\tika-parser-pdf-module\3.2.3\tika-parser-pdf-module-3.2.3.jar;F:\maven-3.6.3-z\repository\org\apache\tika\tika-parser-xmp-commons\3.2.3\tika-parser-xmp-commons-3.2.3.jar;F:\maven-3.6.3-z\repository\org\apache\pdfbox\xmpbox\3.0.5\xmpbox-3.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\pdfbox\pdfbox-tools\3.0.5\pdfbox-tools-3.0.5.jar;F:\maven-3.6.3-z\repository\info\picocli\picocli\4.7.6\picocli-4.7.6.jar;F:\maven-3.6.3-z\repository\org\apache\pdfbox\jempbox\1.8.17\jempbox-1.8.17.jar;F:\maven-3.6.3-z\repository\org\bouncycastle\bcjmail-jdk18on\1.81\bcjmail-jdk18on-1.81.jar;F:\maven-3.6.3-z\repository\org\bouncycastle\bcpkix-jdk18on\1.81\bcpkix-jdk18on-1.81.jar;F:\maven-3.6.3-z\repository\org\bouncycastle\bcutil-jdk18on\1.81\bcutil-jdk18on-1.81.jar;F:\maven-3.6.3-z\repository\org\bouncycastle\bcprov-jdk18on\1.81\bcprov-jdk18on-1.81.jar;F:\maven-3.6.3-z\repository\org\apache\tika\tika-parser-text-module\3.2.3\tika-parser-text-module-3.2.3.jar;F:\maven-3.6.3-z\repository\com\github\albfernandez\juniversalchardet\2.5.0\juniversalchardet-2.5.0.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-csv\1.14.1\commons-csv-1.14.1.jar;F:\maven-3.6.3-z\repository\com\deepoove\poi-tl\1.12.2\poi-tl-1.12.2.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-lang3\3.17.0\commons-lang3-3.17.0.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-transcoder\1.17\batik-transcoder-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-anim\1.17\batik-anim-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-css\1.17\batik-css-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-ext\1.17\batik-ext-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-parser\1.17\batik-parser-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-svg-dom\1.17\batik-svg-dom-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-awt-util\1.17\batik-awt-util-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\xmlgraphics-commons\2.9\xmlgraphics-commons-2.9.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-bridge\1.17\batik-bridge-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-script\1.17\batik-script-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-dom\1.17\batik-dom-1.17.jar;F:\maven-3.6.3-z\repository\xml-apis\xml-apis\1.4.01\xml-apis-1.4.01.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-gvt\1.17\batik-gvt-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-shared-resources\1.17\batik-shared-resources-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-svggen\1.17\batik-svggen-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-util\1.17\batik-util-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-constants\1.17\batik-constants-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-i18n\1.17\batik-i18n-1.17.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-xml\1.17\batik-xml-1.17.jar;F:\maven-3.6.3-z\repository\xml-apis\xml-apis-ext\1.3.04\xml-apis-ext-1.3.04.jar;F:\maven-3.6.3-z\repository\org\apache\xmlgraphics\batik-codec\1.17\batik-codec-1.17.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\weixin4j\2.0.4\weixin4j-2.0.4.jar;F:\maven-3.6.3-z\repository\commons-codec\commons-codec\1.18.0\commons-codec-1.18.0.jar;F:\maven-3.6.3-z\repository\org\slf4j\slf4j-api\2.0.17\slf4j-api-2.0.17.jar;F:\maven-3.6.3-z\repository\org\jdom\jdom\1.1\jdom-1.1.jar;F:\maven-3.6.3-z\repository\org\freemarker\freemarker\2.3.34\freemarker-2.3.34.jar;F:\maven-3.6.3-z\repository\com\google\zxing\javase\3.3.1\javase-3.3.1.jar;F:\maven-3.6.3-z\repository\com\beust\jcommander\1.72\jcommander-1.72.jar;F:\maven-3.6.3-z\repository\com\github\jai-imageio\jai-imageio-core\1.3.1\jai-imageio-core-1.3.1.jar;F:\maven-3.6.3-z\repository\com\alipay\sdk\alipay-sdk-java\3.1.0\alipay-sdk-java-3.1.0.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\jimureport\jimureport-spring-boot3-starter\2.3.0\jimureport-spring-boot3-starter-2.3.0.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\minidao-spring-boot-starter-jsqlparser-4.9\1.10.18\minidao-spring-boot-starter-jsqlparser-4.9-1.10.18.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-jdbc\3.5.5\spring-boot-starter-jdbc-3.5.5.jar;F:\maven-3.6.3-z\repository\com\zaxxer\HikariCP\6.3.2\HikariCP-6.3.2.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-jdbc\6.2.10\spring-jdbc-6.2.10.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\minidao-pe-jsqlparser-4.9\1.10.18\minidao-pe-jsqlparser-4.9-1.10.18.jar;F:\maven-3.6.3-z\repository\commons-collections\commons-collections\3.2.2\commons-collections-3.2.2.jar;F:\maven-3.6.3-z\repository\org\aspectj\aspectjrt\1.9.24\aspectjrt-1.9.24.jar;F:\maven-3.6.3-z\repository\ognl\ognl\3.2.21\ognl-3.2.21.jar;F:\maven-3.6.3-z\repository\org\javassist\javassist\3.25.0-GA\javassist-3.25.0-GA.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\autopoi\2.0.2\autopoi-2.0.2.jar;F:\maven-3.6.3-z\repository\com\google\guava\guava\32.1.3-jre\guava-32.1.3-jre.jar;F:\maven-3.6.3-z\repository\com\google\guava\failureaccess\1.0.1\failureaccess-1.0.1.jar;F:\maven-3.6.3-z\repository\com\google\guava\listenablefuture\9999.0-empty-to-avoid-conflict-with-guava\listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar;F:\maven-3.6.3-z\repository\com\google\errorprone\error_prone_annotations\2.21.1\error_prone_annotations-2.21.1.jar;F:\maven-3.6.3-z\repository\com\google\j2objc\j2objc-annotations\2.8\j2objc-annotations-2.8.jar;F:\maven-3.6.3-z\repository\org\eclipse\angus\jakarta.mail\2.0.4\jakarta.mail-2.0.4.jar;F:\maven-3.6.3-z\repository\org\eclipse\angus\angus-activation\2.0.2\angus-activation-2.0.2.jar;F:\maven-3.6.3-z\repository\commons-fileupload\commons-fileupload\1.5\commons-fileupload-1.5.jar;F:\maven-3.6.3-z\repository\gui\ava\html2image\2.0.1\html2image-2.0.1.jar;F:\maven-3.6.3-z\repository\org\xhtmlrenderer\core-renderer\R8\core-renderer-R8.jar;F:\maven-3.6.3-z\repository\net\sourceforge\nekohtml\nekohtml\1.9.22\nekohtml-1.9.22.jar;F:\maven-3.6.3-z\repository\com\google\zxing\core\3.3.1\core-3.3.1.jar;F:\maven-3.6.3-z\repository\com\aliyun\oss\aliyun-sdk-oss\3.17.3\aliyun-sdk-oss-3.17.3.jar;F:\maven-3.6.3-z\repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;F:\maven-3.6.3-z\repository\org\apache\httpcomponents\httpcore\4.4.16\httpcore-4.4.16.jar;F:\maven-3.6.3-z\repository\org\jdom\jdom2\2.0.6.1\jdom2-2.0.6.1.jar;F:\maven-3.6.3-z\repository\org\codehaus\jettison\jettison\1.5.4\jettison-1.5.4.jar;F:\maven-3.6.3-z\repository\com\aliyun\aliyun-java-sdk-core\4.5.10\aliyun-java-sdk-core-4.5.10.jar;F:\maven-3.6.3-z\repository\org\jacoco\org.jacoco.agent\0.8.5\org.jacoco.agent-0.8.5-runtime.jar;F:\maven-3.6.3-z\repository\org\ini4j\ini4j\0.5.4\ini4j-0.5.4.jar;F:\maven-3.6.3-z\repository\io\opentracing\opentracing-api\0.33.0\opentracing-api-0.33.0.jar;F:\maven-3.6.3-z\repository\io\opentracing\opentracing-util\0.33.0\opentracing-util-0.33.0.jar;F:\maven-3.6.3-z\repository\io\opentracing\opentracing-noop\0.33.0\opentracing-noop-0.33.0.jar;F:\maven-3.6.3-z\repository\com\aliyun\aliyun-java-sdk-ram\3.1.0\aliyun-java-sdk-ram-3.1.0.jar;F:\maven-3.6.3-z\repository\com\aliyun\aliyun-java-sdk-kms\2.11.0\aliyun-java-sdk-kms-2.11.0.jar;F:\maven-3.6.3-z\repository\com\github\librepdf\openpdf\1.3.27\openpdf-1.3.27.jar;F:\maven-3.6.3-z\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\jimureport\jimureport-font\1.2.0\jimureport-font-1.2.0.jar;F:\maven-3.6.3-z\repository\com\googlecode\aviator\aviator\5.2.6\aviator-5.2.6.jar;F:\maven-3.6.3-z\repository\org\apache\httpcomponents\client5\httpclient5\5.5\httpclient5-5.5.jar;F:\maven-3.6.3-z\repository\org\apache\httpcomponents\core5\httpcore5\5.3.4\httpcore5-5.3.4.jar;F:\maven-3.6.3-z\repository\org\apache\httpcomponents\core5\httpcore5-h2\5.3.4\httpcore5-h2-5.3.4.jar;F:\maven-3.6.3-z\repository\com\github\promeg\tinypinyin\2.0.3\tinypinyin-2.0.3.jar;F:\maven-3.6.3-z\repository\org\ahocorasick\ahocorasick\0.3.0\ahocorasick-0.3.0.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\jimureport\jimubi-spring-boot3-starter\2.3.0\jimubi-spring-boot3-starter-2.3.0.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-data-redis\3.5.5\spring-boot-starter-data-redis-3.5.5.jar;F:\maven-3.6.3-z\repository\io\lettuce\lettuce-core\6.6.0.RELEASE\lettuce-core-6.6.0.RELEASE.jar;F:\maven-3.6.3-z\repository\redis\clients\authentication\redis-authx-core\0.1.1-beta2\redis-authx-core-0.1.1-beta2.jar;F:\maven-3.6.3-z\repository\io\netty\netty-common\4.1.124.Final\netty-common-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-handler\4.1.124.Final\netty-handler-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-resolver\4.1.124.Final\netty-resolver-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-buffer\4.1.124.Final\netty-buffer-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-transport-native-unix-common\4.1.124.Final\netty-transport-native-unix-common-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-codec\4.1.124.Final\netty-codec-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\netty\netty-transport\4.1.124.Final\netty-transport-4.1.124.Final.jar;F:\maven-3.6.3-z\repository\io\projectreactor\reactor-core\3.7.9\reactor-core-3.7.9.jar;F:\maven-3.6.3-z\repository\org\springframework\data\spring-data-redis\3.5.3\spring-data-redis-3.5.3.jar;F:\maven-3.6.3-z\repository\org\springframework\data\spring-data-keyvalue\3.5.3\spring-data-keyvalue-3.5.3.jar;F:\maven-3.6.3-z\repository\org\springframework\data\spring-data-commons\3.5.3\spring-data-commons-3.5.3.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-oxm\6.2.10\spring-oxm-6.2.10.jar;F:\maven-3.6.3-z\repository\cn\hutool\hutool-core\5.8.25\hutool-core-5.8.25.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\autopoi-spring-boot-3-starter\2.0.4\autopoi-spring-boot-3-starter-2.0.4.jar;F:\maven-3.6.3-z\repository\org\apache\pdfbox\pdfbox\2.0.30\pdfbox-2.0.30.jar;F:\maven-3.6.3-z\repository\org\apache\pdfbox\fontbox\2.0.30\fontbox-2.0.30.jar;F:\maven-3.6.3-z\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-module-demo\3.9.1\jeecg-module-demo-3.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-boot-base-core\3.9.1\jeecg-boot-base-core-3.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-boot-common\3.9.1\jeecg-boot-common-3.9.1.jar;F:\maven-3.6.3-z\repository\org\apache\commons\commons-pool2\2.12.1\commons-pool2-2.12.1.jar;F:\maven-3.6.3-z\repository\commons-beanutils\commons-beanutils\1.11.0\commons-beanutils-1.11.0.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-web\3.5.5\spring-boot-starter-web-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-json\3.5.5\spring-boot-starter-json-3.5.5.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.19.2\jackson-datatype-jdk8-2.19.2.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.19.2\jackson-datatype-jsr310-2.19.2.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.19.2\jackson-module-parameter-names-2.19.2.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-tomcat\3.5.5\spring-boot-starter-tomcat-3.5.5.jar;F:\maven-3.6.3-z\repository\org\apache\tomcat\embed\tomcat-embed-core\10.1.44\tomcat-embed-core-10.1.44.jar;F:\maven-3.6.3-z\repository\org\apache\tomcat\embed\tomcat-embed-websocket\10.1.44\tomcat-embed-websocket-10.1.44.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-web\6.2.10\spring-web-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-webmvc\6.2.10\spring-webmvc-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-websocket\3.5.5\spring-boot-starter-websocket-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-messaging\6.2.10\spring-messaging-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-websocket\6.2.10\spring-websocket-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-mail\3.5.5\spring-boot-starter-mail-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-context-support\6.2.10\spring-context-support-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-aop\3.5.5\spring-boot-starter-aop-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-aop\6.2.10\spring-aop-6.2.10.jar;F:\maven-3.6.3-z\repository\org\aspectj\aspectjweaver\1.9.24\aspectjweaver-1.9.24.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-actuator\3.5.5\spring-boot-starter-actuator-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-actuator-autoconfigure\3.5.5\spring-boot-actuator-autoconfigure-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-actuator\3.5.5\spring-boot-actuator-3.5.5.jar;F:\maven-3.6.3-z\repository\io\micrometer\micrometer-observation\1.15.3\micrometer-observation-1.15.3.jar;F:\maven-3.6.3-z\repository\io\micrometer\micrometer-commons\1.15.3\micrometer-commons-1.15.3.jar;F:\maven-3.6.3-z\repository\io\micrometer\micrometer-jakarta9\1.15.3\micrometer-jakarta9-1.15.3.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-validation\3.5.5\spring-boot-starter-validation-3.5.5.jar;F:\maven-3.6.3-z\repository\org\apache\tomcat\embed\tomcat-embed-el\10.1.44\tomcat-embed-el-10.1.44.jar;F:\maven-3.6.3-z\repository\org\hibernate\validator\hibernate-validator\8.0.3.Final\hibernate-validator-8.0.3.Final.jar;F:\maven-3.6.3-z\repository\jakarta\validation\jakarta.validation-api\3.0.2\jakarta.validation-api-3.0.2.jar;F:\maven-3.6.3-z\repository\io\micrometer\micrometer-registry-prometheus\1.15.3\micrometer-registry-prometheus-1.15.3.jar;F:\maven-3.6.3-z\repository\io\micrometer\micrometer-core\1.15.3\micrometer-core-1.15.3.jar;F:\maven-3.6.3-z\repository\org\hdrhistogram\HdrHistogram\2.2.2\HdrHistogram-2.2.2.jar;F:\maven-3.6.3-z\repository\org\latencyutils\LatencyUtils\2.0.3\LatencyUtils-2.0.3.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-core\1.3.10\prometheus-metrics-core-1.3.10.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-model\1.3.10\prometheus-metrics-model-1.3.10.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-config\1.3.10\prometheus-metrics-config-1.3.10.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-tracer-common\1.3.10\prometheus-metrics-tracer-common-1.3.10.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-exposition-formats\1.3.10\prometheus-metrics-exposition-formats-1.3.10.jar;F:\maven-3.6.3-z\repository\io\prometheus\prometheus-metrics-exposition-textformats\1.3.10\prometheus-metrics-exposition-textformats-1.3.10.jar;F:\maven-3.6.3-z\repository\commons-io\commons-io\2.20.0\commons-io-2.20.0.jar;F:\maven-3.6.3-z\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-freemarker\3.5.5\spring-boot-starter-freemarker-3.5.5.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-spring-boot3-starter\3.5.12\mybatis-plus-spring-boot3-starter-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus\3.5.12\mybatis-plus-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-core\3.5.12\mybatis-plus-core-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-annotation\3.5.12\mybatis-plus-annotation-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-spring\3.5.12\mybatis-plus-spring-3.5.12.jar;F:\maven-3.6.3-z\repository\org\mybatis\mybatis\3.5.19\mybatis-3.5.19.jar;F:\maven-3.6.3-z\repository\org\mybatis\mybatis-spring\3.0.4\mybatis-spring-3.0.4.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-spring-boot-autoconfigure\3.5.12\mybatis-plus-spring-boot-autoconfigure-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-jsqlparser-4.9\3.5.12\mybatis-plus-jsqlparser-4.9-3.5.12.jar;F:\maven-3.6.3-z\repository\com\github\jsqlparser\jsqlparser\4.9\jsqlparser-4.9.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-jsqlparser-common\3.5.12\mybatis-plus-jsqlparser-common-3.5.12.jar;F:\maven-3.6.3-z\repository\com\baomidou\mybatis-plus-extension\3.5.12\mybatis-plus-extension-3.5.12.jar;F:\maven-3.6.3-z\repository\com\alibaba\druid-spring-boot-3-starter\1.2.24\druid-spring-boot-3-starter-1.2.24.jar;F:\maven-3.6.3-z\repository\com\alibaba\druid\1.2.24\druid-1.2.24.jar;F:\maven-3.6.3-z\repository\com\baomidou\dynamic-datasource-spring-boot3-starter\4.3.1\dynamic-datasource-spring-boot3-starter-4.3.1.jar;F:\maven-3.6.3-z\repository\com\baomidou\dynamic-datasource-spring-boot-common\4.3.1\dynamic-datasource-spring-boot-common-4.3.1.jar;F:\maven-3.6.3-z\repository\com\baomidou\dynamic-datasource-spring\4.3.1\dynamic-datasource-spring-4.3.1.jar;F:\maven-3.6.3-z\repository\com\baomidou\dynamic-datasource-creator\4.3.1\dynamic-datasource-creator-4.3.1.jar;F:\maven-3.6.3-z\repository\mysql\mysql-connector-java\8.0.27\mysql-connector-java-8.0.27.jar;F:\maven-3.6.3-z\repository\com\google\protobuf\protobuf-java\3.11.4\protobuf-java-3.11.4.jar;F:\maven-3.6.3-z\repository\com\microsoft\sqlserver\mssql-jdbc\12.10.1.jre11\mssql-jdbc-12.10.1.jre11.jar;F:\maven-3.6.3-z\repository\com\oracle\ojdbc6\11.2.0.3\ojdbc6-11.2.0.3.jar;F:\maven-3.6.3-z\repository\org\postgresql\postgresql\42.2.25\postgresql-42.2.25.jar;F:\maven-3.6.3-z\repository\org\checkerframework\checker-qual\3.5.0\checker-qual-3.5.0.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\kingbase8\9.0.0\kingbase8-9.0.0.jar;F:\maven-3.6.3-z\repository\com\dameng\DmJdbcDriver18\8.1.3.140\DmJdbcDriver18-8.1.3.140.jar;F:\maven-3.6.3-z\repository\com\dameng\DmDialect-for-hibernate5.0\8.1.3.140\DmDialect-for-hibernate5.0-8.1.3.140.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-quartz\3.5.5\spring-boot-starter-quartz-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-tx\6.2.10\spring-tx-6.2.10.jar;F:\maven-3.6.3-z\repository\org\quartz-scheduler\quartz\2.5.0\quartz-2.5.0.jar;F:\maven-3.6.3-z\repository\com\auth0\java-jwt\4.5.0\java-jwt-4.5.0.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-spring-boot-starter\2.0.5\shiro-spring-boot-starter-2.0.5-jakarta.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-spring\2.0.5\shiro-spring-2.0.5-jakarta.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-core\2.0.5\shiro-core-2.0.5-jakarta.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-lang\2.0.5\shiro-lang-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-cache\2.0.5\shiro-cache-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-crypto-hash\2.0.5\shiro-crypto-hash-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-crypto-core\2.0.5\shiro-crypto-core-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\crypto\shiro-hashes-argon2\2.0.5\shiro-hashes-argon2-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\crypto\shiro-hashes-bcrypt\2.0.5\shiro-hashes-bcrypt-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-crypto-cipher\2.0.5\shiro-crypto-cipher-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-config-core\2.0.5\shiro-config-core-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-config-ogdl\2.0.5\shiro-config-ogdl-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-event\2.0.5\shiro-event-2.0.5.jar;F:\maven-3.6.3-z\repository\org\apache\shiro\shiro-web\2.0.5\shiro-web-2.0.5-jakarta.jar;F:\maven-3.6.3-z\repository\org\owasp\encoder\encoder\1.3.1\encoder-1.3.1.jar;F:\maven-3.6.3-z\repository\org\crazycake\shiro-redis\3.2.3\shiro-redis-3.2.3.jar;F:\maven-3.6.3-z\repository\redis\clients\jedis\3.8.0\jedis-3.8.0.jar;F:\maven-3.6.3-z\repository\com\github\xiaoymin\knife4j-openapi3-ui\4.5.0\knife4j-openapi3-ui-4.5.0.jar;F:\maven-3.6.3-z\repository\org\springdoc\springdoc-openapi-starter-webmvc-ui\2.7.0\springdoc-openapi-starter-webmvc-ui-2.7.0.jar;F:\maven-3.6.3-z\repository\org\springdoc\springdoc-openapi-starter-webmvc-api\2.7.0\springdoc-openapi-starter-webmvc-api-2.7.0.jar;F:\maven-3.6.3-z\repository\org\springdoc\springdoc-openapi-starter-common\2.7.0\springdoc-openapi-starter-common-2.7.0.jar;F:\maven-3.6.3-z\repository\io\swagger\core\v3\swagger-core-jakarta\2.2.25\swagger-core-jakarta-2.2.25.jar;F:\maven-3.6.3-z\repository\io\swagger\core\v3\swagger-annotations-jakarta\2.2.25\swagger-annotations-jakarta-2.2.25.jar;F:\maven-3.6.3-z\repository\io\swagger\core\v3\swagger-models-jakarta\2.2.25\swagger-models-jakarta-2.2.25.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\dataformat\jackson-dataformat-yaml\2.19.2\jackson-dataformat-yaml-2.19.2.jar;F:\maven-3.6.3-z\repository\org\webjars\swagger-ui\5.18.2\swagger-ui-5.18.2.jar;F:\maven-3.6.3-z\repository\org\webjars\webjars-locator-lite\1.1.0\webjars-locator-lite-1.1.0.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot\codegenerate\1.5.5\codegenerate-1.5.5.jar;F:\maven-3.6.3-z\repository\io\minio\minio\8.5.7\minio-8.5.7.jar;F:\maven-3.6.3-z\repository\com\carrotsearch\thirdparty\simple-xml-safe\2.7.1\simple-xml-safe-2.7.1.jar;F:\maven-3.6.3-z\repository\org\xerial\snappy\snappy-java\1.1.10.5\snappy-java-1.1.10.5.jar;F:\maven-3.6.3-z\repository\com\aliyun\aliyun-java-sdk-dysmsapi\2.1.0\aliyun-java-sdk-dysmsapi-2.1.0.jar;F:\maven-3.6.3-z\repository\com\google\code\gson\gson\2.13.1\gson-2.13.1.jar;F:\maven-3.6.3-z\repository\com\xkcoding\justauth\justauth-spring-boot-starter\1.4.0\justauth-spring-boot-starter-1.4.0.jar;F:\maven-3.6.3-z\repository\me\zhyd\oauth\JustAuth\1.16.1\JustAuth-1.16.1.jar;F:\maven-3.6.3-z\repository\com\xkcoding\http\simple-http\1.0.3\simple-http-1.0.3.jar;F:\maven-3.6.3-z\repository\com\squareup\okhttp3\okhttp\4.4.1\okhttp-4.4.1.jar;F:\maven-3.6.3-z\repository\com\squareup\okio\okio\2.4.3\okio-2.4.3.jar;F:\maven-3.6.3-z\repository\org\jetbrains\kotlin\kotlin-stdlib-common\1.9.25\kotlin-stdlib-common-1.9.25.jar;F:\maven-3.6.3-z\repository\org\jetbrains\kotlin\kotlin-stdlib\1.9.25\kotlin-stdlib-1.9.25.jar;F:\maven-3.6.3-z\repository\org\jetbrains\annotations\13.0\annotations-13.0.jar;F:\maven-3.6.3-z\repository\com\fasterxml\jackson\module\jackson-module-kotlin\2.19.2\jackson-module-kotlin-2.19.2.jar;F:\maven-3.6.3-z\repository\org\jetbrains\kotlin\kotlin-reflect\1.9.25\kotlin-reflect-1.9.25.jar;F:\maven-3.6.3-z\repository\cn\hutool\hutool-crypto\5.8.25\hutool-crypto-5.8.25.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-boot-starter-chatgpt\3.9.1.1\jeecg-boot-starter-chatgpt-3.9.1.1.jar;F:\maven-3.6.3-z\repository\com\tencentcloudapi\tencentcloud-sdk-java-sms\3.1.407\tencentcloud-sdk-java-sms-3.1.407.jar;F:\maven-3.6.3-z\repository\com\tencentcloudapi\tencentcloud-sdk-java-common\3.1.407\tencentcloud-sdk-java-common-3.1.407.jar;F:\maven-3.6.3-z\repository\com\squareup\okhttp\okhttp\2.7.5\okhttp-2.7.5.jar;F:\maven-3.6.3-z\repository\com\squareup\okhttp\logging-interceptor\2.7.5\logging-interceptor-2.7.5.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-module-print\3.9.1\jeecg-module-print-3.9.1.jar;F:\maven-3.6.3-z\repository\org\jeecgframework\boot3\jeecg-module-xslmes\3.9.1\jeecg-module-xslmes-3.9.1.jar;F:\maven-3.6.3-z\repository\org\flywaydb\flyway-core\7.15.0\flyway-core-7.15.0.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-properties-migrator\3.5.5\spring-boot-properties-migrator-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot\3.5.5\spring-boot-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-context\6.2.10\spring-context-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-beans\6.2.10\spring-beans-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-expression\6.2.10\spring-expression-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-configuration-metadata\3.5.5\spring-boot-configuration-metadata-3.5.5.jar;F:\maven-3.6.3-z\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;F:\maven-3.6.3-z\repository\jakarta\servlet\jakarta.servlet-api\6.0.0\jakarta.servlet-api-6.0.0.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-test\3.5.5\spring-boot-starter-test-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter\3.5.5\spring-boot-starter-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-autoconfigure\3.5.5\spring-boot-autoconfigure-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-starter-logging\3.5.5\spring-boot-starter-logging-3.5.5.jar;F:\maven-3.6.3-z\repository\ch\qos\logback\logback-classic\1.5.18\logback-classic-1.5.18.jar;F:\maven-3.6.3-z\repository\ch\qos\logback\logback-core\1.5.18\logback-core-1.5.18.jar;F:\maven-3.6.3-z\repository\org\apache\logging\log4j\log4j-to-slf4j\2.24.3\log4j-to-slf4j-2.24.3.jar;F:\maven-3.6.3-z\repository\org\slf4j\jul-to-slf4j\2.0.17\jul-to-slf4j-2.0.17.jar;F:\maven-3.6.3-z\repository\jakarta\annotation\jakarta.annotation-api\2.1.1\jakarta.annotation-api-2.1.1.jar;F:\maven-3.6.3-z\repository\org\yaml\snakeyaml\2.4\snakeyaml-2.4.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-test\3.5.5\spring-boot-test-3.5.5.jar;F:\maven-3.6.3-z\repository\org\springframework\boot\spring-boot-test-autoconfigure\3.5.5\spring-boot-test-autoconfigure-3.5.5.jar;F:\maven-3.6.3-z\repository\com\jayway\jsonpath\json-path\2.9.0\json-path-2.9.0.jar;F:\maven-3.6.3-z\repository\jakarta\xml\bind\jakarta.xml.bind-api\4.0.2\jakarta.xml.bind-api-4.0.2.jar;F:\maven-3.6.3-z\repository\jakarta\activation\jakarta.activation-api\2.1.3\jakarta.activation-api-2.1.3.jar;F:\maven-3.6.3-z\repository\net\minidev\json-smart\2.5.2\json-smart-2.5.2.jar;F:\maven-3.6.3-z\repository\net\minidev\accessors-smart\2.5.2\accessors-smart-2.5.2.jar;F:\maven-3.6.3-z\repository\org\assertj\assertj-core\3.27.4\assertj-core-3.27.4.jar;F:\maven-3.6.3-z\repository\org\awaitility\awaitility\4.2.2\awaitility-4.2.2.jar;F:\maven-3.6.3-z\repository\org\hamcrest\hamcrest\3.0\hamcrest-3.0.jar;F:\maven-3.6.3-z\repository\org\junit\jupiter\junit-jupiter\5.12.2\junit-jupiter-5.12.2.jar;F:\maven-3.6.3-z\repository\org\junit\jupiter\junit-jupiter-api\5.12.2\junit-jupiter-api-5.12.2.jar;F:\maven-3.6.3-z\repository\org\junit\jupiter\junit-jupiter-params\5.12.2\junit-jupiter-params-5.12.2.jar;F:\maven-3.6.3-z\repository\org\junit\jupiter\junit-jupiter-engine\5.12.2\junit-jupiter-engine-5.12.2.jar;F:\maven-3.6.3-z\repository\org\mockito\mockito-core\5.17.0\mockito-core-5.17.0.jar;F:\maven-3.6.3-z\repository\net\bytebuddy\byte-buddy-agent\1.17.7\byte-buddy-agent-1.17.7.jar;F:\maven-3.6.3-z\repository\org\objenesis\objenesis\3.3\objenesis-3.3.jar;F:\maven-3.6.3-z\repository\org\mockito\mockito-junit-jupiter\5.17.0\mockito-junit-jupiter-5.17.0.jar;F:\maven-3.6.3-z\repository\org\skyscreamer\jsonassert\1.5.3\jsonassert-1.5.3.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-core\6.2.10\spring-core-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-jcl\6.2.10\spring-jcl-6.2.10.jar;F:\maven-3.6.3-z\repository\org\springframework\spring-test\6.2.10\spring-test-6.2.10.jar;F:\maven-3.6.3-z\repository\org\xmlunit\xmlunit-core\2.10.3\xmlunit-core-2.10.3.jar;F:\maven-3.6.3-z\repository\org\junit\platform\junit-platform-launcher\1.12.2\junit-platform-launcher-1.12.2.jar;F:\maven-3.6.3-z\repository\org\junit\platform\junit-platform-engine\1.12.2\junit-platform-engine-1.12.2.jar;F:\maven-3.6.3-z\repository\org\opentest4j\opentest4j\1.3.0\opentest4j-1.3.0.jar;F:\maven-3.6.3-z\repository\org\junit\platform\junit-platform-commons\1.12.2\junit-platform-commons-1.12.2.jar;F:\maven-3.6.3-z\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;F:\maven-3.6.3-z\repository\org\projectlombok\lombok\1.18.38\lombok-1.18.38.jar;F:\maven-3.6.3-z\repository\com\alibaba\fastjson\2.0.57\fastjson-2.0.57.jar;F:\maven-3.6.3-z\repository\com\alibaba\fastjson2\fastjson2-extension\2.0.57\fastjson2-extension-2.0.57.jar;F:\maven-3.6.3-z\repository\com\alibaba\fastjson2\fastjson2\2.0.57\fastjson2-2.0.57.jar;F:\maven-3.6.3-z\repository\org\commonmark\commonmark\0.17.0\commonmark-0.17.0.jar
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml b/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
index ff35027..2e4dfff 100644
--- a/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/pom.xml
@@ -30,6 +30,12 @@
jeecg-module-print
${jeecgboot.version}
+
+
+ org.jeecgframework.boot3
+ jeecg-module-xslmes
+ ${jeecgboot.version}
+
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_10__mes_xsl_vehicle_unit_id.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_10__mes_xsl_vehicle_unit_id.sql
new file mode 100644
index 0000000..2e8e7ca
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_10__mes_xsl_vehicle_unit_id.sql
@@ -0,0 +1,5 @@
+-- 车辆管理:关联单位主键
+
+ALTER TABLE `mes_xsl_vehicle`
+ ADD COLUMN `unit_id` varchar(36) DEFAULT NULL COMMENT '单位ID(mes_xsl_unit.id)' AFTER `load_capacity`,
+ ADD KEY `idx_mes_xsl_vehicle_unit` (`unit_id`);
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_11__mes_xsl_supplier.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_11__mes_xsl_supplier.sql
new file mode 100644
index 0000000..e27077b
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_11__mes_xsl_supplier.sql
@@ -0,0 +1,79 @@
+-- MES 供应商管理:表 + 字典 + 菜单 + 管理员角色授权(幂等)
+
+CREATE TABLE IF NOT EXISTS `mes_xsl_supplier` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `supplier_code` varchar(64) NOT NULL COMMENT '编码',
+ `supplier_name` varchar(100) NOT NULL COMMENT '名称',
+ `erp_code` varchar(64) DEFAULT NULL COMMENT 'ERP编码',
+ `status` varchar(10) DEFAULT '1' COMMENT '状态(字典 xslmes_supplier_status)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_supplier_code` (`supplier_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES供应商管理';
+
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES供应商状态', 'xslmes_supplier_status', '停用、启用', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_supplier_status' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '停用', '0', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_supplier_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '0');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '启用', '1', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_supplier_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000350', '1900000000000000300', '供应商管理', '/xslmes/mesXslSupplier', 'xslmes/mesXslSupplier/MesXslSupplierList', 1, NULL, NULL, 1, NULL, '0', 4.00, 0, 'ant-design:shop-outlined', 1, 1, 0, 0, 'MES供应商管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000350');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000351', '1900000000000000350', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000351');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000352', '1900000000000000350', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000352');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000353', '1900000000000000350', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000353');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000354', '1900000000000000350', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000354');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000355', '1900000000000000350', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000355');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000356', '1900000000000000350', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000356');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000357', '1900000000000000350', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000357');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000430', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000350', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000430');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000431', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000351', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000431');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000432', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000352', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000432');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000433', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000353', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000433');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000434', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000354', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000434');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000435', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000355', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000435');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000436', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000356', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000436');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000437', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000357', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000437');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_12__mes_xsl_vehicle_belong.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_12__mes_xsl_vehicle_belong.sql
new file mode 100644
index 0000000..fa9f66f
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_12__mes_xsl_vehicle_belong.sql
@@ -0,0 +1,23 @@
+-- 车辆管理:车辆归属字典 + 供应商/司机字段
+
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES车辆归属', 'xslmes_vehicle_belong', '客户、供应商、本公司', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_vehicle_belong' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '客户', '1', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_vehicle_belong' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '供应商', '2', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_vehicle_belong' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '2');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '本公司', '3', 3, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_vehicle_belong' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '3');
+
+ALTER TABLE `mes_xsl_vehicle`
+ ADD COLUMN `vehicle_belong` varchar(10) DEFAULT NULL COMMENT '车辆归属(字典 xslmes_vehicle_belong)' AFTER `plate_number`,
+ ADD COLUMN `supplier_id` varchar(36) DEFAULT NULL COMMENT '供应商ID' AFTER `customer_short_name`,
+ ADD COLUMN `supplier_name` varchar(200) DEFAULT NULL COMMENT '供应商名称' AFTER `supplier_id`,
+ ADD COLUMN `driver_name` varchar(64) DEFAULT NULL COMMENT '司机' AFTER `vehicle_height`,
+ ADD COLUMN `driver_phone` varchar(32) DEFAULT NULL COMMENT '联系电话' AFTER `driver_name`,
+ ADD KEY `idx_mes_xsl_vehicle_belong` (`vehicle_belong`);
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_13__mes_xsl_vehicle_tare_comment.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_13__mes_xsl_vehicle_tare_comment.sql
new file mode 100644
index 0000000..a985dd9
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_13__mes_xsl_vehicle_tare_comment.sql
@@ -0,0 +1,4 @@
+-- 车辆管理:列注释「车辆自重」改为「车辆皮重」(字段名不变 tare_weight_kg)
+
+ALTER TABLE `mes_xsl_vehicle`
+ MODIFY COLUMN `tare_weight_kg` decimal(12,3) DEFAULT NULL COMMENT '车辆皮重(KG)';
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_14__mes_xsl_unit_category_length_group.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_14__mes_xsl_unit_category_length_group.sql
new file mode 100644
index 0000000..f1e58ea
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_14__mes_xsl_unit_category_length_group.sql
@@ -0,0 +1,5 @@
+-- 单位分类:补「长度组」根分类(与 V3.9.2_9 种子一致;已存在 category_code=length_group 则跳过)
+
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000504', '0', 'length_group', '长度组', 4, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'length_group');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_15__mes_xsl_unit_tenant_align.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_15__mes_xsl_unit_tenant_align.sql
new file mode 100644
index 0000000..55d1024
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_15__mes_xsl_unit_tenant_align.sql
@@ -0,0 +1,15 @@
+-- 单位模块:将 tenant_id 从 NULL 对齐为 0,避免多租户拦截器下查询不到数据
+-- 说明:MyBatis 租户插件追加 WHERE tenant_id = ?,NULL 行不会被命中 → 左侧分类树缺「长度组」、列表「所属分类」为空
+
+UPDATE `mes_xsl_unit_category` SET `tenant_id` = 0 WHERE `tenant_id` IS NULL;
+UPDATE `mes_xsl_unit` SET `tenant_id` = 0 WHERE `tenant_id` IS NULL;
+
+-- 补「长度组」根分类(若不存在;tenant_id=0 与默认租户一致)
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000504', '0', 'length_group', '长度组', 4, '1', 0, 'admin', NOW(), 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'length_group');
+
+-- 常见长度单位若未挂分类,挂到长度组
+UPDATE `mes_xsl_unit`
+SET `category_id` = '1900000000000000504', `tenant_id` = COALESCE(`tenant_id`, 0)
+WHERE `unit_code` IN ('m', 'km', 'cm') AND (`category_id` IS NULL OR `category_id` = '');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_16__mes_xsl_supplier_short_remark_vehicle_supplier_short.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_16__mes_xsl_supplier_short_remark_vehicle_supplier_short.sql
new file mode 100644
index 0000000..c5108ef
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_16__mes_xsl_supplier_short_remark_vehicle_supplier_short.sql
@@ -0,0 +1,16 @@
+-- 供应商:简称、备注;车辆:供应商简称(选择供应商后展示)
+
+ALTER TABLE `mes_xsl_supplier`
+ ADD COLUMN `supplier_short_name` varchar(64) DEFAULT NULL COMMENT '简称' AFTER `supplier_name`;
+
+ALTER TABLE `mes_xsl_supplier`
+ ADD COLUMN `remark` varchar(500) DEFAULT NULL COMMENT '备注' AFTER `erp_code`;
+
+ALTER TABLE `mes_xsl_vehicle`
+ ADD COLUMN `supplier_short_name` varchar(64) DEFAULT NULL COMMENT '供应商简称' AFTER `supplier_name`;
+
+-- 已有车辆:从供应商回填简称(无简称时用名称)
+UPDATE `mes_xsl_vehicle` v
+INNER JOIN `mes_xsl_supplier` s ON v.`supplier_id` = s.`id`
+SET v.`supplier_short_name` = COALESCE(NULLIF(TRIM(s.`supplier_short_name`), ''), s.`supplier_name`)
+WHERE v.`supplier_id` IS NOT NULL;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_17__mes_xsl_instrument.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_17__mes_xsl_instrument.sql
new file mode 100644
index 0000000..2d30d1b
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_17__mes_xsl_instrument.sql
@@ -0,0 +1,91 @@
+-- MES 器具管理:表 + 字典 + 菜单 + 管理员角色授权(幂等)
+
+CREATE TABLE IF NOT EXISTS `mes_xsl_instrument` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `barcode` varchar(64) NOT NULL COMMENT '编号/条码',
+ `status` varchar(10) DEFAULT '1' COMMENT '状态(字典 xslmes_instrument_status)',
+ `remark` varchar(500) DEFAULT NULL COMMENT '备注',
+ `spec_model` varchar(64) DEFAULT NULL COMMENT '规格型号(字典 xslmes_instrument_spec)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_instrument_barcode` (`barcode`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES器具管理';
+
+-- 状态:启用/停用
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES器具状态', 'xslmes_instrument_status', '停用、启用', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_instrument_status' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '停用', '0', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_instrument_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '0');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '启用', '1', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_instrument_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+
+-- 规格型号字典(示例项,可后续在字典管理追加)
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES器具规格型号', 'xslmes_instrument_spec', '器具规格尺寸等', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_instrument_spec' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '130*100*23.6', '130*100*23.6', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_instrument_spec' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '130*100*23.6');
+
+-- 菜单(父级 MES:1900000000000000300)
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000370', '1900000000000000300', '器具管理', '/xslmes/mesXslInstrument', 'xslmes/mesXslInstrument/MesXslInstrumentList', 1, NULL, NULL, 1, NULL, '0', 5.00, 0, 'ant-design:experiment-outlined', 1, 1, 0, 0, 'MES器具管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000370');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000371', '1900000000000000370', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000371');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000372', '1900000000000000370', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000372');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000373', '1900000000000000370', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000373');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000374', '1900000000000000370', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000374');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000375', '1900000000000000370', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000375');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000376', '1900000000000000370', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000376');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000377', '1900000000000000370', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000377');
+
+-- 管理员角色授权
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000450', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000370', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000450');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000451', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000371', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000451');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000452', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000372', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000452');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000453', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000373', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000453');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000454', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000374', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000454');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000455', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000375', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000455');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000456', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000376', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000456');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000457', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000377', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000457');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_18__mes_xsl_status_enable_zero.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_18__mes_xsl_status_enable_zero.sql
new file mode 100644
index 0000000..96f4811
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_18__mes_xsl_status_enable_zero.sql
@@ -0,0 +1,61 @@
+-- MES 各模块「启用/停用」状态统一为:0=启用,1=停用(客户字典保留 2=删除)
+-- 说明:将原 0=停用、1=启用 的业务数据与字典项做互换
+
+-- ========== 业务表 status 互换 ==========
+UPDATE `mes_xsl_supplier` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE `status` END WHERE `status` IN ('0','1');
+UPDATE `mes_xsl_supplier` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+UPDATE `mes_xsl_vehicle` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE `status` END WHERE `status` IN ('0','1');
+UPDATE `mes_xsl_vehicle` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+UPDATE `mes_xsl_unit` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE `status` END WHERE `status` IN ('0','1');
+UPDATE `mes_xsl_unit` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+UPDATE `mes_xsl_unit_category` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE `status` END WHERE `status` IN ('0','1');
+UPDATE `mes_xsl_unit_category` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+UPDATE `mes_xsl_instrument` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE `status` END WHERE `status` IN ('0','1');
+UPDATE `mes_xsl_instrument` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+-- 客户:含「删除」字典值 2,仅 0/1 互换
+UPDATE `mes_xsl_customer` SET `status` = CASE `status` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' WHEN '2' THEN '2' ELSE `status` END WHERE `status` IN ('0','1','2');
+UPDATE `mes_xsl_customer` SET `status` = CASE `status` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE `status` END;
+
+-- ========== 字典项 item_value / item_text ==========
+-- 二元状态字典
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` IN ('xslmes_supplier_status', 'xslmes_vehicle_status', 'xslmes_unit_status', 'xslmes_instrument_status')
+SET i.`item_value` = CASE i.`item_value` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' ELSE i.`item_value` END
+WHERE i.`item_value` IN ('0','1');
+
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` IN ('xslmes_supplier_status', 'xslmes_vehicle_status', 'xslmes_unit_status', 'xslmes_instrument_status')
+SET i.`item_value` = CASE i.`item_value` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE i.`item_value` END
+WHERE i.`item_value` IN ('__T0__','__T1__');
+
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` IN ('xslmes_supplier_status', 'xslmes_vehicle_status', 'xslmes_unit_status', 'xslmes_instrument_status')
+SET i.`item_text` = CASE i.`item_value` WHEN '0' THEN '启用' WHEN '1' THEN '停用' ELSE i.`item_text` END;
+
+-- 客户状态(0启用 1停用 2删除)
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` = 'xslmes_customer_status'
+SET i.`item_value` = CASE i.`item_value` WHEN '0' THEN '__T0__' WHEN '1' THEN '__T1__' WHEN '2' THEN '2' ELSE i.`item_value` END
+WHERE i.`item_value` IN ('0','1','2');
+
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` = 'xslmes_customer_status'
+SET i.`item_value` = CASE i.`item_value` WHEN '__T0__' THEN '1' WHEN '__T1__' THEN '0' ELSE i.`item_value` END
+WHERE i.`item_value` IN ('__T0__','__T1__');
+
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` = 'xslmes_customer_status'
+SET i.`item_text` = CASE i.`item_value` WHEN '0' THEN '启用' WHEN '1' THEN '停用' WHEN '2' THEN '删除' ELSE i.`item_text` END;
+
+-- ========== 列默认值改为「启用」=0 ==========
+ALTER TABLE `mes_xsl_supplier` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_supplier_status,0启用1停用)';
+ALTER TABLE `mes_xsl_vehicle` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_vehicle_status,0启用1停用)';
+ALTER TABLE `mes_xsl_unit` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_unit_status,0启用1停用)';
+ALTER TABLE `mes_xsl_unit_category` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_unit_status,0启用1停用)';
+ALTER TABLE `mes_xsl_instrument` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_instrument_status,0启用1停用)';
+ALTER TABLE `mes_xsl_customer` MODIFY COLUMN `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_customer_status,0启用1停用2删除)';
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_20__mes_xsl_customer_tenant_id_null_to_zero.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_20__mes_xsl_customer_tenant_id_null_to_zero.sql
new file mode 100644
index 0000000..b0e6eb6
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_20__mes_xsl_customer_tenant_id_null_to_zero.sql
@@ -0,0 +1,3 @@
+-- 多租户拦截器按 tenant_id=当前租户查询/更新;列为 NULL 时与 tenant_id=0 无法匹配,导致列表能展示异常数据或更新 0 行(视数据与 SQL 而定)
+-- 将空租户统一为 0,与默认租户上下文一致
+UPDATE `mes_xsl_customer` SET `tenant_id` = 0 WHERE `tenant_id` IS NULL;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_21__mes_xsl_customer_dict_item_text_align.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_21__mes_xsl_customer_dict_item_text_align.sql
new file mode 100644
index 0000000..534731b
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_21__mes_xsl_customer_dict_item_text_align.sql
@@ -0,0 +1,12 @@
+-- 客户状态字典文案与后端/前端约定对齐:item_value 0=启用 1=停用 2=删除
+-- 说明:早期 V3.9.2_4 曾将「启用/停用」文案与 value 写反,导致库中 status=0 仍显示「停用」
+
+UPDATE `sys_dict_item` i
+INNER JOIN `sys_dict` d ON i.`dict_id` = d.`id` AND d.`dict_code` = 'xslmes_customer_status' AND d.`del_flag` = 0
+SET i.`item_text` = CASE i.`item_value`
+ WHEN '0' THEN '启用'
+ WHEN '1' THEN '停用'
+ WHEN '2' THEN '删除'
+ ELSE i.`item_text`
+END
+WHERE i.`item_value` IN ('0', '1', '2');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_22__mes_xsl_vehicle_supplier_short_name_safe.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_22__mes_xsl_vehicle_supplier_short_name_safe.sql
new file mode 100644
index 0000000..055816f
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_22__mes_xsl_vehicle_supplier_short_name_safe.sql
@@ -0,0 +1,21 @@
+-- 车辆表补充 supplier_short_name(兼容未成功执行 V3.9.2_16 的库,幂等)
+
+SET @col_exists := (
+ SELECT COUNT(*) FROM information_schema.COLUMNS
+ WHERE TABLE_SCHEMA = DATABASE()
+ AND TABLE_NAME = 'mes_xsl_vehicle'
+ AND COLUMN_NAME = 'supplier_short_name'
+);
+SET @ddl := IF(@col_exists = 0,
+ 'ALTER TABLE `mes_xsl_vehicle` ADD COLUMN `supplier_short_name` varchar(64) DEFAULT NULL COMMENT ''供应商简称'' AFTER `supplier_name`',
+ 'SELECT 1');
+PREPARE stmt FROM @ddl;
+EXECUTE stmt;
+DEALLOCATE PREPARE stmt;
+
+-- 已有车辆:用供应商名称回填简称(不依赖供应商表是否已有 supplier_short_name 列)
+UPDATE `mes_xsl_vehicle` v
+INNER JOIN `mes_xsl_supplier` s ON v.`supplier_id` = s.`id`
+SET v.`supplier_short_name` = s.`supplier_name`
+WHERE v.`supplier_id` IS NOT NULL
+ AND (v.`supplier_short_name` IS NULL OR TRIM(v.`supplier_short_name`) = '');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_23__mes_xsl_customer_update_status_perm.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_23__mes_xsl_customer_update_status_perm.sql
new file mode 100644
index 0000000..24f5516
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_23__mes_xsl_customer_update_status_perm.sql
@@ -0,0 +1,9 @@
+-- 客户管理:列表启用/停用按钮权限(与供应商管理 xslmes:mes_xsl_supplier:updateStatus 同级)
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000317', '1900000000000000301', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000317');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000399', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000317', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000399');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_24__mes_xsl_menu_button_permissions.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_24__mes_xsl_menu_button_permissions.sql
new file mode 100644
index 0000000..2b79056
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_24__mes_xsl_menu_button_permissions.sql
@@ -0,0 +1,80 @@
+-- MES XSL:将各列表菜单下的「按钮权限」幂等写入/对齐 sys_permission(menu_type=2,parent_id 指向对应页面菜单)
+-- 覆盖:客户、车辆、单位(含分类按钮)、供应商、器具 —— 含编辑、删除、导出、导入、停用启用及添加、批量删除
+-- 若历史数据中 parent_id 错位或缺行,本脚本通过 INSERT ... ON DUPLICATE KEY UPDATE 修复,便于「系统管理-菜单管理-按钮授权」中展示与分配
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`) VALUES
+-- 客户管理 1900000000000000301
+('1900000000000000311', '1900000000000000301', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000312', '1900000000000000301', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000313', '1900000000000000301', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000314', '1900000000000000301', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000315', '1900000000000000301', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000316', '1900000000000000301', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000317', '1900000000000000301', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+-- 车辆管理 1900000000000000320
+('1900000000000000321', '1900000000000000320', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000322', '1900000000000000320', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000323', '1900000000000000320', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000324', '1900000000000000320', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000325', '1900000000000000320', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000326', '1900000000000000320', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000327', '1900000000000000320', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+-- 单位管理 1900000000000000330(含单位分类相关按钮)
+('1900000000000000331', '1900000000000000330', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000332', '1900000000000000330', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000333', '1900000000000000330', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000334', '1900000000000000330', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000335', '1900000000000000330', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000336', '1900000000000000330', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000337', '1900000000000000330', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000338', '1900000000000000330', '新增分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:add', '1', 8.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000339', '1900000000000000330', '编辑分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:edit', '1', 9.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000340', '1900000000000000330', '删除分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:delete', '1', 10.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+-- 供应商管理 1900000000000000350
+('1900000000000000351', '1900000000000000350', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000352', '1900000000000000350', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000353', '1900000000000000350', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000354', '1900000000000000350', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000355', '1900000000000000350', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000356', '1900000000000000350', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000357', '1900000000000000350', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_supplier:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+-- 器具管理 1900000000000000370
+('1900000000000000371', '1900000000000000370', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000372', '1900000000000000370', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000373', '1900000000000000370', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000374', '1900000000000000370', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000375', '1900000000000000370', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000376', '1900000000000000370', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0),
+('1900000000000000377', '1900000000000000370', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_instrument:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0)
+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`),
+ `sort_no` = VALUES(`sort_no`),
+ `del_flag` = VALUES(`del_flag`),
+ `status` = VALUES(`status`),
+ `update_by` = VALUES(`update_by`),
+ `update_time` = VALUES(`update_time`);
+
+-- 默认管理员角色:为上述按钮补授权(已存在 role_id+permission_id 则跳过)
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT REPLACE(UUID(), '-', ''), 'f6817f48af4fb3af11b9e8bf182f618b', x.`pid`, NULL, NOW(), '127.0.0.1'
+FROM (
+ SELECT '1900000000000000311' AS `pid` UNION ALL SELECT '1900000000000000312' UNION ALL SELECT '1900000000000000313' UNION ALL SELECT '1900000000000000314'
+ UNION ALL SELECT '1900000000000000315' UNION ALL SELECT '1900000000000000316' UNION ALL SELECT '1900000000000000317'
+ UNION ALL SELECT '1900000000000000321' UNION ALL SELECT '1900000000000000322' UNION ALL SELECT '1900000000000000323' UNION ALL SELECT '1900000000000000324'
+ UNION ALL SELECT '1900000000000000325' UNION ALL SELECT '1900000000000000326' UNION ALL SELECT '1900000000000000327'
+ UNION ALL SELECT '1900000000000000331' UNION ALL SELECT '1900000000000000332' UNION ALL SELECT '1900000000000000333' UNION ALL SELECT '1900000000000000334'
+ UNION ALL SELECT '1900000000000000335' UNION ALL SELECT '1900000000000000336' UNION ALL SELECT '1900000000000000337'
+ UNION ALL SELECT '1900000000000000338' UNION ALL SELECT '1900000000000000339' UNION ALL SELECT '1900000000000000340'
+ UNION ALL SELECT '1900000000000000351' UNION ALL SELECT '1900000000000000352' UNION ALL SELECT '1900000000000000353' UNION ALL SELECT '1900000000000000354'
+ UNION ALL SELECT '1900000000000000355' UNION ALL SELECT '1900000000000000356' UNION ALL SELECT '1900000000000000357'
+ UNION ALL SELECT '1900000000000000371' UNION ALL SELECT '1900000000000000372' UNION ALL SELECT '1900000000000000373' UNION ALL SELECT '1900000000000000374'
+ UNION ALL SELECT '1900000000000000375' UNION ALL SELECT '1900000000000000376' UNION ALL SELECT '1900000000000000377'
+) x
+WHERE NOT EXISTS (
+ SELECT 1 FROM `sys_role_permission` rp
+ WHERE rp.`role_id` = 'f6817f48af4fb3af11b9e8bf182f618b' AND rp.`permission_id` = x.`pid`
+);
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_25__mes_xsl_submenu_is_leaf_for_button_tree.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_25__mes_xsl_submenu_is_leaf_for_button_tree.sql
new file mode 100644
index 0000000..954e973
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_25__mes_xsl_submenu_is_leaf_for_button_tree.sql
@@ -0,0 +1,15 @@
+-- 菜单管理「权限树」不显示子级按钮的原因:SysPermissionController#getTreeModelList 仅在节点 is_leaf=0 时继续递归,
+-- 才能把 parent_id 指向该菜单的 menu_type=2 记录挂到树上。MES XSL 各列表页子菜单原先 is_leaf=1,递归被跳过,按钮永不出现在树下。
+-- 含按钮子权限的页面菜单应设为 is_leaf=0(非叶子节点);按钮行本身仍为 is_leaf=1(见各按钮 INSERT)。
+
+UPDATE `sys_permission`
+SET `is_leaf` = 0
+WHERE `id` IN (
+ '1900000000000000301',
+ '1900000000000000320',
+ '1900000000000000330',
+ '1900000000000000350',
+ '1900000000000000370'
+)
+ AND `menu_type` = 1
+ AND `del_flag` = 0;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_26__mes_xsl_warehouse.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_26__mes_xsl_warehouse.sql
new file mode 100644
index 0000000..4b4ed86
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_26__mes_xsl_warehouse.sql
@@ -0,0 +1,117 @@
+-- MES 仓库管理:表 + 仓库分类字典 + 菜单 + 管理员角色授权(幂等)
+-- 状态复用字典 xslmes_unit_status(0 启用 1 停用)
+
+CREATE TABLE IF NOT EXISTS `mes_xsl_warehouse` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `warehouse_code` varchar(100) NOT NULL COMMENT '仓库编码',
+ `warehouse_name` varchar(200) NOT NULL COMMENT '仓库名称',
+ `warehouse_category` varchar(32) NOT NULL COMMENT '仓库分类(字典 xslmes_warehouse_category)',
+ `erp_code` varchar(100) DEFAULT NULL COMMENT 'ERP编码',
+ `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_unit_status,0启用1停用)',
+ `customer_id` varchar(36) DEFAULT NULL COMMENT '客户ID(分类为客户库时)',
+ `customer_short_name` varchar(200) DEFAULT NULL COMMENT '客户简称',
+ `supplier_id` varchar(36) DEFAULT NULL COMMENT '供应商ID(分类为供应商库时)',
+ `supplier_short_name` varchar(100) DEFAULT NULL COMMENT '供应商简称',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_warehouse_code` (`warehouse_code`),
+ KEY `idx_mes_xsl_warehouse_category` (`warehouse_category`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES仓库管理';
+
+-- 仓库分类
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES仓库分类', 'xslmes_warehouse_category', '原材料库、成品库等', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_warehouse_category' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '原材料库', 'RAW', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'RAW');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '成品库', 'FINISHED', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'FINISHED');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '待检库', 'PENDING_QC', 3, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'PENDING_QC');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '合格品库', 'QUALIFIED', 4, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'QUALIFIED');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '不合格品库', 'UNQUALIFIED', 5, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'UNQUALIFIED');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '废料库', 'WASTE', 6, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'WASTE');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '烘胶房', 'RUBBER', 7, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'RUBBER');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '客户库', 'CUSTOMER', 8, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'CUSTOMER');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '供应商库', 'SUPPLIER', 9, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_warehouse_category' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'SUPPLIER');
+
+-- 菜单(父级 MES:1900000000000000300)
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000380', '1900000000000000300', '仓库管理', '/xslmes/mesXslWarehouse', 'xslmes/mesXslWarehouse/MesXslWarehouseList', 1, NULL, NULL, 1, NULL, '0', 6.00, 0, 'ant-design:home-outlined', 0, 1, 0, 0, 'MES仓库管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000380');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000381', '1900000000000000380', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000381');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000382', '1900000000000000380', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000382');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000383', '1900000000000000380', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000383');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000384', '1900000000000000380', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000384');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000385', '1900000000000000380', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000385');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000386', '1900000000000000380', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000386');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000387', '1900000000000000380', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000387');
+
+-- 管理员角色授权
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000460', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000380', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000460');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000461', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000381', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000461');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000462', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000382', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000462');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000463', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000383', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000463');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000464', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000384', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000464');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000465', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000385', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000465');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000466', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000386', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000466');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000467', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000387', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000467');
+
+-- 含按钮子权限的列表菜单 is_leaf=0,权限树可展开显示按钮(与 V3.9.2_25 一致)
+UPDATE `sys_permission`
+SET `is_leaf` = 0
+WHERE `id` = '1900000000000000380'
+ AND `menu_type` = 1
+ AND `del_flag` = 0;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_27__mes_xsl_warehouse_sys_category.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_27__mes_xsl_warehouse_sys_category.sql
new file mode 100644
index 0000000..fe4f25e
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_27__mes_xsl_warehouse_sys_category.sql
@@ -0,0 +1,67 @@
+-- MES 仓库分类改为「分类字典」sys_category(根编码 XSLMES_WH),并迁移原字典 item_value 数据
+-- 一楼库:成品、待检、合格品、废品、不合格品;二楼仓库:烘胶房、原材料、废品、客户库、供应商库
+
+-- 根节点
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000001', '0', 'MES仓库分类', 'XSLMES_WH', '1', 'admin', NOW()
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH');
+
+-- 一楼库、二楼仓库
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000002', '1991000000000000001', '一楼库', 'XSLMES_WH_F1', '1', 'admin', NOW()
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1');
+
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000003', '1991000000000000001', '二楼仓库', 'XSLMES_WH_F2', '1', 'admin', NOW()
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2');
+
+-- 一楼库 → 子类
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000011', '1991000000000000002', '成品库', 'XSLMES_WH_F1_CP', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1_CP');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000012', '1991000000000000002', '待检库', 'XSLMES_WH_F1_DJ', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1_DJ');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000013', '1991000000000000002', '合格品库', 'XSLMES_WH_F1_HG', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1_HG');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000014', '1991000000000000002', '废品库', 'XSLMES_WH_F1_FP', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1_FP');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000015', '1991000000000000002', '不合格品库', 'XSLMES_WH_F1_BHG', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F1_BHG');
+
+-- 二楼仓库 → 子类
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000021', '1991000000000000003', '烘胶房', 'XSLMES_WH_F2_HJ', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2_HJ');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000022', '1991000000000000003', '原材料库', 'XSLMES_WH_F2_YCL', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2_YCL');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000023', '1991000000000000003', '废品库', 'XSLMES_WH_F2_FP', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2_FP');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000024', '1991000000000000003', '客户库', 'XSLMES_WH_F2_KH', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2_KH');
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1991000000000000025', '1991000000000000003', '供应商库', 'XSLMES_WH_F2_GYS', '0', 'admin', NOW()
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_WH_F2_GYS');
+
+-- 将 mes_xsl_warehouse 中原字典 item_value 转为分类字典 id(仅当仍为旧值时)
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000011' WHERE `warehouse_category` = 'FINISHED';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000012' WHERE `warehouse_category` = 'PENDING_QC';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000013' WHERE `warehouse_category` = 'QUALIFIED';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000014' WHERE `warehouse_category` = 'WASTE';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000015' WHERE `warehouse_category` = 'UNQUALIFIED';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000022' WHERE `warehouse_category` = 'RAW';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000021' WHERE `warehouse_category` = 'RUBBER';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000024' WHERE `warehouse_category` = 'CUSTOMER';
+UPDATE `mes_xsl_warehouse` SET `warehouse_category` = '1991000000000000025' WHERE `warehouse_category` = 'SUPPLIER';
+
+ALTER TABLE `mes_xsl_warehouse`
+ MODIFY COLUMN `warehouse_category` varchar(36) NOT NULL COMMENT '仓库分类(sys_category.id,根编码 XSLMES_WH)';
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_28__mes_xsl_warehouse_category_buttons.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_28__mes_xsl_warehouse_category_buttons.sql
new file mode 100644
index 0000000..dcb1d00
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_28__mes_xsl_warehouse_category_buttons.sql
@@ -0,0 +1,25 @@
+-- 仓库管理:侧栏维护「分类字典」子树所需按钮权限(走 /sys/category,与系统分类字典一致)
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000388', '1900000000000000380', '新增仓库分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse_category:add', '1', 8.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000388');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000389', '1900000000000000380', '编辑仓库分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse_category:edit', '1', 9.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000389');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000390', '1900000000000000380', '删除仓库分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_warehouse_category:delete', '1', 10.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000390');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000468', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000388', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000468');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000469', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000389', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000469');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000470', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000390', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000470');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_29__mes_xsl_unit_sys_category.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_29__mes_xsl_unit_sys_category.sql
new file mode 100644
index 0000000..c83bced
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_29__mes_xsl_unit_sys_category.sql
@@ -0,0 +1,44 @@
+-- MES 单位分类:由独立表 mes_xsl_unit_category 迁入系统分类字典 sys_category(根编码 XSLMES_UNIT)
+-- 保留原分类主键 id,无需批量更新 mes_xsl_unit.category_id
+
+-- 根节点
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT '1992000000000000001', '0', 'MES单位分类', 'XSLMES_UNIT', '1', 'admin', NOW()
+FROM DUAL
+WHERE NOT EXISTS (SELECT 1 FROM `sys_category` WHERE `code` = 'XSLMES_UNIT');
+
+-- 从旧表迁入(仅当表仍存在时;id 与原表一致)
+INSERT INTO `sys_category` (`id`, `pid`, `name`, `code`, `has_child`, `create_by`, `create_time`)
+SELECT
+ c.`id`,
+ CASE
+ WHEN IFNULL(NULLIF(TRIM(c.`parent_id`), ''), '0') IN ('0', '') THEN '1992000000000000001'
+ ELSE c.`parent_id`
+ END,
+ c.`category_name`,
+ CONCAT('XSLMES_UNIT_', UPPER(REPLACE(REPLACE(c.`category_code`, '-', '_'), ' ', '_'))),
+ CASE
+ WHEN EXISTS (
+ SELECT 1 FROM `mes_xsl_unit_category` c2
+ WHERE c2.`parent_id` = c.`id` AND IFNULL(c2.`del_flag`, 0) = 0
+ ) THEN '1'
+ ELSE '0'
+ END,
+ IFNULL(c.`create_by`, 'admin'),
+ IFNULL(c.`create_time`, NOW())
+FROM `mes_xsl_unit_category` c
+WHERE IFNULL(c.`del_flag`, 0) = 0
+ AND NOT EXISTS (SELECT 1 FROM `sys_category` sc WHERE sc.`id` = c.`id`);
+
+-- 同步 has_child(含根节点)
+UPDATE `sys_category` p
+SET `has_child` = '1'
+WHERE EXISTS (SELECT 1 FROM `sys_category` ch WHERE ch.`pid` = p.`id`);
+UPDATE `sys_category` p
+SET `has_child` = '0'
+WHERE NOT EXISTS (SELECT 1 FROM `sys_category` ch WHERE ch.`pid` = p.`id`);
+
+ALTER TABLE `mes_xsl_unit`
+ MODIFY COLUMN `category_id` varchar(36) NOT NULL COMMENT '所属分类(sys_category.id,根编码 XSLMES_UNIT)';
+
+DROP TABLE IF EXISTS `mes_xsl_unit_category`;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_4__mes_xsl_customer.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_4__mes_xsl_customer.sql
new file mode 100644
index 0000000..56fa49f
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_4__mes_xsl_customer.sql
@@ -0,0 +1,104 @@
+-- MES 客户管理:表 + 字典 + 菜单 + 管理员角色授权(幂等)
+
+-- ========== 表 ==========
+CREATE TABLE IF NOT EXISTS `mes_xsl_customer` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `customer_code` varchar(100) NOT NULL COMMENT '客户编码',
+ `customer_name` varchar(200) NOT NULL COMMENT '客户名称',
+ `customer_region` varchar(32) DEFAULT NULL COMMENT '客户区域',
+ `erp_code` varchar(100) DEFAULT NULL COMMENT 'ERP编码',
+ `status` varchar(10) DEFAULT '0' COMMENT '状态(字典 xslmes_customer_status,0启用1停用)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `customer_desc` varchar(500) DEFAULT NULL COMMENT '客户描述',
+ `iz_enable` tinyint(1) DEFAULT '1' COMMENT '是否启用(1是0否)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_customer_code` (`customer_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES客户管理';
+
+-- ========== 字典:客户区域 ==========
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES客户区域', 'xslmes_customer_region', 'MES客户区域', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_customer_region' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '平度', 'pingdu', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'pingdu');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '高密', 'gaomi', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'gaomi');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '青岛', 'qingdao', 3, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'qingdao');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '烟台', 'yantai', 4, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'yantai');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '东营', 'dongying', 5, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'dongying');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '黄岛', 'huangdao', 6, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'huangdao');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '青州', 'qingzhou', 7, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'qingzhou');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '嘉兴市', 'jiaxing', 8, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_region' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = 'jiaxing');
+
+-- ========== 字典:客户状态(启用/停用;删除为逻辑删除 del_flag,不在此字典选“删除”) ==========
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES客户状态', 'xslmes_customer_status', '启用、停用、删除(删除建议配合逻辑删除)', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_customer_status' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '启用', '0', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '0');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '停用', '1', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '删除', '2', 3, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_customer_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '2');
+
+-- ========== 菜单 ==========
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000300', '', 'MES XSL', '/xslmes', 'layouts/default/index', 1, NULL, '/xslmes/mesXslCustomer', 0, NULL, '0', 80.00, 0, 'ant-design:appstore-outlined', 0, 0, 0, 0, 'MES XSL 业务', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000300');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000301', '1900000000000000300', '客户管理', '/xslmes/mesXslCustomer', 'xslmes/mesXslCustomer/MesXslCustomerList', 1, NULL, NULL, 1, NULL, '0', 1.00, 0, 'ant-design:team-outlined', 1, 1, 0, 0, 'MES客户管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000301');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000311', '1900000000000000301', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000311');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000312', '1900000000000000301', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000312');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000313', '1900000000000000301', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000313');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000314', '1900000000000000301', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000314');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000315', '1900000000000000301', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000315');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000316', '1900000000000000301', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_customer:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000316');
+
+-- ========== 管理员角色授权(admin 角色 id 与项目一致) ==========
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000391', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000300', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000392', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000301', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000393', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000311', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000394', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000312', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000395', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000313', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000396', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000314', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000397', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000315', NULL, NOW(), '127.0.0.1');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`) VALUES ('1900000000000000398', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000316', NULL, NOW(), '127.0.0.1');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_5__mes_xsl_customer_short_name.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_5__mes_xsl_customer_short_name.sql
new file mode 100644
index 0000000..d48b063
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_5__mes_xsl_customer_short_name.sql
@@ -0,0 +1,3 @@
+-- 客户管理:新增「客户简称」
+ALTER TABLE `mes_xsl_customer`
+ ADD COLUMN `customer_short_name` varchar(100) DEFAULT NULL COMMENT '客户简称' AFTER `customer_name`;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_6__mes_xsl_customer_sync_status_iz_enable.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_6__mes_xsl_customer_sync_status_iz_enable.sql
new file mode 100644
index 0000000..a72df2a
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_6__mes_xsl_customer_sync_status_iz_enable.sql
@@ -0,0 +1,4 @@
+-- 历史数据:status(字典)与 iz_enable 对齐,避免列表「状态」与启用逻辑不一致
+UPDATE `mes_xsl_customer`
+SET `iz_enable` = CASE WHEN `status` = '1' THEN 1 ELSE 0 END
+WHERE `del_flag` = 0;
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_7__mes_xsl_vehicle.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_7__mes_xsl_vehicle.sql
new file mode 100644
index 0000000..1ed931a
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_7__mes_xsl_vehicle.sql
@@ -0,0 +1,87 @@
+-- MES 车辆管理:表 + 字典 + 菜单 + 管理员角色授权(幂等)
+
+CREATE TABLE IF NOT EXISTS `mes_xsl_vehicle` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `plate_number` varchar(32) NOT NULL COMMENT '车牌号',
+ `tare_weight_kg` decimal(12,3) DEFAULT NULL COMMENT '车辆自重(KG)',
+ `load_capacity` decimal(12,3) DEFAULT NULL COMMENT '装载量',
+ `load_unit` varchar(32) DEFAULT NULL COMMENT '单位',
+ `customer_ids` varchar(1000) DEFAULT NULL COMMENT '客户ID,多选逗号分隔',
+ `customer_short_name` varchar(1000) DEFAULT NULL COMMENT '客户简称展示',
+ `vehicle_length` decimal(10,3) DEFAULT NULL COMMENT '车长',
+ `vehicle_width` decimal(10,3) DEFAULT NULL COMMENT '车宽',
+ `vehicle_height` decimal(10,3) DEFAULT NULL COMMENT '车高',
+ `status` varchar(10) DEFAULT '1' COMMENT '状态(字典 xslmes_vehicle_status)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_vehicle_plate` (`plate_number`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES车辆管理';
+
+-- 字典:车辆状态
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES车辆状态', 'xslmes_vehicle_status', '停用、启用', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_vehicle_status' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '停用', '0', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_vehicle_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '0');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '启用', '1', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_vehicle_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+
+-- 菜单(父级 MES XSL)
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000320', '1900000000000000300', '车辆管理', '/xslmes/mesXslVehicle', 'xslmes/mesXslVehicle/MesXslVehicleList', 1, NULL, NULL, 1, NULL, '0', 2.00, 0, 'ant-design:car-outlined', 1, 1, 0, 0, 'MES车辆管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000320');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000321', '1900000000000000320', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000321');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000322', '1900000000000000320', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000322');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000323', '1900000000000000320', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000323');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000324', '1900000000000000320', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000324');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000325', '1900000000000000320', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000325');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000326', '1900000000000000320', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000326');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000327', '1900000000000000320', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_vehicle:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000327');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000401', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000320', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000401');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000402', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000321', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000402');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000403', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000322', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000403');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000404', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000323', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000404');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000405', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000324', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000405');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000406', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000325', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000406');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000407', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000326', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000407');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000408', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000327', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000408');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_8__mes_xsl_unit.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_8__mes_xsl_unit.sql
new file mode 100644
index 0000000..f546cb4
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_8__mes_xsl_unit.sql
@@ -0,0 +1,122 @@
+-- MES 单位分类 + 单位:表 + 字典 + 菜单 + 管理员角色授权(幂等)
+
+-- 单位分类(树)
+CREATE TABLE IF NOT EXISTS `mes_xsl_unit_category` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `parent_id` varchar(36) NOT NULL DEFAULT '0' COMMENT '父级ID,0为根',
+ `category_code` varchar(64) NOT NULL COMMENT '分类编码',
+ `category_name` varchar(100) NOT NULL COMMENT '分类名称',
+ `sort_no` int DEFAULT '0' COMMENT '排序号',
+ `status` varchar(10) DEFAULT '1' COMMENT '状态(字典 xslmes_unit_status)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_unit_category_parent` (`parent_id`),
+ KEY `idx_mes_xsl_unit_category_code` (`category_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES单位分类';
+
+-- 单位
+CREATE TABLE IF NOT EXISTS `mes_xsl_unit` (
+ `id` varchar(36) NOT NULL COMMENT '主键',
+ `unit_code` varchar(64) NOT NULL COMMENT '编码',
+ `unit_name` varchar(100) NOT NULL COMMENT '名称',
+ `erp_code` varchar(64) DEFAULT NULL COMMENT 'ERP编码',
+ `category_id` varchar(36) NOT NULL COMMENT '所属分类ID',
+ `unit_desc` text COMMENT '描述',
+ `status` varchar(10) DEFAULT '1' COMMENT '状态(字典 xslmes_unit_status)',
+ `del_flag` tinyint(1) DEFAULT '0' COMMENT '删除标志(0正常1删除)',
+ `create_by` varchar(50) DEFAULT NULL COMMENT '创建人',
+ `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+ `update_by` varchar(50) DEFAULT NULL COMMENT '更新人',
+ `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+ `tenant_id` int DEFAULT NULL COMMENT '租户ID',
+ PRIMARY KEY (`id`),
+ KEY `idx_mes_xsl_unit_category` (`category_id`),
+ KEY `idx_mes_xsl_unit_code` (`unit_code`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='MES单位';
+
+-- 字典:单位/分类状态(启用、停用)
+INSERT INTO `sys_dict` (`id`, `dict_name`, `dict_code`, `description`, `del_flag`, `create_by`, `create_time`, `type`, `tenant_id`)
+SELECT REPLACE(UUID(), '-', ''), 'MES单位状态', 'xslmes_unit_status', '停用、启用', 0, 'admin', NOW(), 0, 0
+WHERE NOT EXISTS (SELECT 1 FROM `sys_dict` WHERE `dict_code` = 'xslmes_unit_status' AND `del_flag` = 0);
+
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '停用', '0', 1, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_unit_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '0');
+INSERT INTO `sys_dict_item` (`id`, `dict_id`, `item_text`, `item_value`, `sort_order`, `status`, `create_by`, `create_time`)
+SELECT REPLACE(UUID(), '-', ''), d.id, '启用', '1', 2, 1, 'admin', NOW() FROM `sys_dict` d
+WHERE d.`dict_code` = 'xslmes_unit_status' AND NOT EXISTS (SELECT 1 FROM `sys_dict_item` i WHERE i.`dict_id` = d.id AND i.`item_value` = '1');
+
+-- 菜单(父级 MES XSL)
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000330', '1900000000000000300', '单位管理', '/xslmes/mesXslUnit', 'xslmes/mesXslUnit/MesXslUnitList', 1, NULL, NULL, 1, NULL, '0', 3.00, 0, 'ant-design:cluster-outlined', 1, 1, 0, 0, 'MES单位管理', 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000330');
+
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000331', '1900000000000000330', '添加', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:add', '1', 1.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000331');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000332', '1900000000000000330', '编辑', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:edit', '1', 2.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000332');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000333', '1900000000000000330', '删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:delete', '1', 3.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000333');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000334', '1900000000000000330', '批量删除', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:deleteBatch', '1', 4.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000334');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000335', '1900000000000000330', '导出', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:exportXls', '1', 5.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000335');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000336', '1900000000000000330', '导入', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:importExcel', '1', 6.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000336');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000337', '1900000000000000330', '停用启用', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit:updateStatus', '1', 7.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000337');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000338', '1900000000000000330', '新增分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:add', '1', 8.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000338');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000339', '1900000000000000330', '编辑分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:edit', '1', 9.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000339');
+INSERT INTO `sys_permission` (`id`, `parent_id`, `name`, `url`, `component`, `is_route`, `component_name`, `redirect`, `menu_type`, `perms`, `perms_type`, `sort_no`, `always_show`, `icon`, `is_leaf`, `keep_alive`, `hidden`, `hide_tab`, `description`, `create_by`, `create_time`, `update_by`, `update_time`, `del_flag`, `rule_flag`, `status`, `internal_or_external`)
+SELECT '1900000000000000340', '1900000000000000330', '删除分类', NULL, NULL, 0, NULL, NULL, 2, 'xslmes:mes_xsl_unit_category:delete', '1', 10.00, 0, NULL, 1, 0, 0, 0, NULL, 'admin', NOW(), 'admin', NOW(), 0, 0, '1', 0
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_permission` WHERE `id` = '1900000000000000340');
+
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000410', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000330', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000410');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000411', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000331', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000411');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000412', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000332', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000412');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000413', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000333', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000413');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000414', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000334', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000414');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000415', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000335', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000415');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000416', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000336', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000416');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000417', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000337', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000417');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000418', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000338', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000418');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000419', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000339', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000419');
+INSERT INTO `sys_role_permission` (`id`, `role_id`, `permission_id`, `data_rule_ids`, `operate_date`, `operate_ip`)
+SELECT '1900000000000000420', 'f6817f48af4fb3af11b9e8bf182f618b', '1900000000000000340', NULL, NOW(), '127.0.0.1'
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `sys_role_permission` WHERE `id` = '1900000000000000420');
diff --git a/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_9__mes_xsl_unit_seed_data.sql b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_9__mes_xsl_unit_seed_data.sql
new file mode 100644
index 0000000..14f01e6
--- /dev/null
+++ b/jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/flyway/sql/mysql/V3.9.2_9__mes_xsl_unit_seed_data.sql
@@ -0,0 +1,85 @@
+-- MES 单位分类 + 单位:初始化数据(来自业务单位清单,幂等)
+
+-- 固定主键便于关联;若已存在同编码则跳过
+-- 分类:数量组、重量组、时间组、长度组
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000501', '0', 'qty_group', '数量组', 1, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'qty_group');
+
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000502', '0', 'weight_group', '重量组', 2, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'weight_group');
+
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000503', '0', 'time_group', '时间组', 3, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'time_group');
+
+INSERT INTO `mes_xsl_unit_category` (`id`, `parent_id`, `category_code`, `category_name`, `sort_no`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000504', '0', 'length_group', '长度组', 4, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit_category` WHERE `category_code` = 'length_group');
+
+-- 单位(编码、名称、ERP编码、所属分类、状态启用)
+-- 数量组 1900000000000000501
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000511', 'tuo', '托', NULL, '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'tuo');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000512', 'tao', '套', 'tao', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'tao');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000513', 'tai', '台', 'tai', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'tai');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000514', 'Pcs', 'Pcs', 'Pcs', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'Pcs');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000515', 'ml', '毫升', 'ml', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'ml');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000516', 'liang', '辆', 'liang', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'liang');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000517', 'L', '升', 'L', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'L');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000518', 'dozen', '打', 'dozen', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'dozen');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000519', 'double', '双', 'double', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'double');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000520', 'dong', '栋', 'dong', '1900000000000000501', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'dong');
+
+-- 重量组 1900000000000000502
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000521', 'ton', '吨', 'ton', '1900000000000000502', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'ton');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000522', 'kg', '千克', 'kg', '1900000000000000502', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'kg');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000523', 'g', '克', 'g', '1900000000000000502', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'g');
+
+-- 时间组 1900000000000000503
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000524', 'second', '秒', 'second', '1900000000000000503', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'second');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000525', 'minute', '分', 'minute', '1900000000000000503', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'minute');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000526', 'hour', '时', 'hour', '1900000000000000503', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'hour');
+
+-- 长度组 1900000000000000504
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000527', 'm', '米', 'm', '1900000000000000504', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'm');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000528', 'km', '千米', 'km', '1900000000000000504', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'km');
+INSERT INTO `mes_xsl_unit` (`id`, `unit_code`, `unit_name`, `erp_code`, `category_id`, `unit_desc`, `status`, `del_flag`, `create_by`, `create_time`, `tenant_id`)
+SELECT '1900000000000000529', 'cm', '厘米', 'cm', '1900000000000000504', NULL, '1', 0, 'admin', NOW(), NULL
+FROM DUAL WHERE NOT EXISTS (SELECT 1 FROM `mes_xsl_unit` WHERE `unit_code` = 'cm');
diff --git a/jeecgboot-vue3/.env.development b/jeecgboot-vue3/.env.development
index fb3498c..048ab79 100644
--- a/jeecgboot-vue3/.env.development
+++ b/jeecgboot-vue3/.env.development
@@ -5,14 +5,15 @@ VITE_USE_MOCK = true
VITE_PUBLIC_PATH = /
-# 跨域代理,您可以配置多个 ,请注意,没有换行符
-VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
+# 跨域代理:前缀须与 VITE_GLOB_API_URL 一致,且 rewrite 后路径需包含后端 context-path(/jeecg-boot)
+# 详见 build/vite/proxy.ts
+VITE_PROXY = [["/jeecg-boot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot
-#后台接口父地址(必填)
-VITE_GLOB_API_URL=/jeecgboot
+#后台接口父地址(必填),与 server.servlet.context-path 一致,避免仅去掉别名前缀后缺少 /jeecg-boot
+VITE_GLOB_API_URL=/jeecg-boot
# 接口前缀
VITE_GLOB_API_URL_PREFIX=
diff --git a/jeecgboot-vue3/.env.docker b/jeecgboot-vue3/.env.docker
index 74f6ee8..b2c0c7b 100644
--- a/jeecgboot-vue3/.env.docker
+++ b/jeecgboot-vue3/.env.docker
@@ -13,7 +13,7 @@ VITE_BUILD_COMPRESS = 'gzip'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
#后台接口父地址(必填)
-VITE_GLOB_API_URL=/jeecgboot
+VITE_GLOB_API_URL=/jeecg-boot
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-system:8080/jeecg-boot
diff --git a/jeecgboot-vue3/.env.dockercloud b/jeecgboot-vue3/.env.dockercloud
index d719398..ada0634 100644
--- a/jeecgboot-vue3/.env.dockercloud
+++ b/jeecgboot-vue3/.env.dockercloud
@@ -13,7 +13,7 @@ VITE_BUILD_COMPRESS = 'gzip'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
#后台接口父地址(必填)
-VITE_GLOB_API_URL=/jeecgboot
+VITE_GLOB_API_URL=/jeecg-boot
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://jeecg-boot-gateway:9999
diff --git a/jeecgboot-vue3/.env.production b/jeecgboot-vue3/.env.production
index f355372..c56d4eb 100644
--- a/jeecgboot-vue3/.env.production
+++ b/jeecgboot-vue3/.env.production
@@ -13,7 +13,7 @@ VITE_BUILD_COMPRESS = 'gzip'
VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE = false
#后台接口父地址(必填)
-VITE_GLOB_API_URL=/jeecgboot
+VITE_GLOB_API_URL=/jeecg-boot
#后台接口全路径地址(必填)
VITE_GLOB_DOMAIN_URL=http://127.0.0.1:8080/jeecg-boot
diff --git a/jeecgboot-vue3/build/vite/proxy.ts b/jeecgboot-vue3/build/vite/proxy.ts
index 8525397..2c43eba 100644
--- a/jeecgboot-vue3/build/vite/proxy.ts
+++ b/jeecgboot-vue3/build/vite/proxy.ts
@@ -20,12 +20,30 @@ export function createProxy(list: ProxyList = []) {
for (const [prefix, target] of list) {
const isHttps = httpsRE.test(target);
+ // 若 target 带路径(如 http://localhost:8080/jeecg-boot),需拼回转发路径:
+ // 否则 rewrite 去掉 /jeecgboot 后只剩 /xslmes/...,缺少 context-path,后端会报 No static resource。
+ let proxyTarget = target;
+ let targetPathPrefix = '';
+ try {
+ const u = new URL(target);
+ const p = (u.pathname || '').replace(/\/$/, '');
+ if (p) {
+ targetPathPrefix = p;
+ proxyTarget = `${u.protocol}//${u.host}`;
+ }
+ } catch {
+ /* 非标准 URL 时保持原 target */
+ }
+
// https://github.com/http-party/node-http-proxy#options
ret[prefix] = {
- target: target,
+ target: proxyTarget,
changeOrigin: true,
ws: true,
- rewrite: (path) => path.replace(new RegExp(`^${prefix}`), ''),
+ rewrite: (path) => {
+ const stripped = path.replace(new RegExp(`^${prefix}`), '');
+ return targetPathPrefix ? `${targetPathPrefix}${stripped}` : stripped;
+ },
// https is require secure=false
...(isHttps ? { secure: false } : {}),
};
diff --git a/jeecgboot-vue3/src/components/Form/src/hooks/useForm.ts b/jeecgboot-vue3/src/components/Form/src/hooks/useForm.ts
index a260be8..b23836c 100644
--- a/jeecgboot-vue3/src/components/Form/src/hooks/useForm.ts
+++ b/jeecgboot-vue3/src/components/Form/src/hooks/useForm.ts
@@ -72,9 +72,8 @@ export function useForm(props?: Props): UseFormReturnType {
},
resetFields: async () => {
- getForm().then(async (form) => {
- await form.resetFields();
- });
+ const form = await getForm();
+ await form.resetFields();
},
removeSchemaByFiled: async (field: string | string[]) => {
diff --git a/jeecgboot-vue3/src/utils/http/axios/index.ts b/jeecgboot-vue3/src/utils/http/axios/index.ts
index e6e922f..757affc 100644
--- a/jeecgboot-vue3/src/utils/http/axios/index.ts
+++ b/jeecgboot-vue3/src/utils/http/axios/index.ts
@@ -151,6 +151,36 @@ const transform: AxiosTransform = {
}
}
+ /**
+ * 单体 / 集成部署:页面在 http://host/jeecg-boot/ 下时,若仅用「以 / 开头的相对 URL」,
+ * 浏览器会解析到 http://host/jeecg-boot/... 或误解析到 http://host/xslmes/...(缺少 context-path),
+ * 后端报 No static resource。使用完整 domainUrl 作 axios baseURL,url 只保留 servlet 内路径。
+ */
+ if (
+ !isStartWithHttp &&
+ !globSetting.isQiankunMicro &&
+ globSetting.domainUrl &&
+ /^https?:\/\//.test(globSetting.domainUrl) &&
+ config.url &&
+ typeof config.url === 'string'
+ ) {
+ try {
+ const du = new URL(globSetting.domainUrl);
+ const ctx = (du.pathname || '').replace(/\/$/, '');
+ config.baseURL = globSetting.domainUrl.replace(/\/$/, '');
+ let pathOnly = config.url as string;
+ if (ctx && (pathOnly === ctx || pathOnly.startsWith(ctx + '/'))) {
+ pathOnly = pathOnly.slice(ctx.length) || '/';
+ }
+ if (!pathOnly.startsWith('/')) {
+ pathOnly = '/' + pathOnly;
+ }
+ config.url = pathOnly;
+ } catch {
+ /* 忽略 URL 解析异常 */
+ }
+ }
+
return config;
},
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.api.ts
new file mode 100644
index 0000000..32b0e48
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.api.ts
@@ -0,0 +1,56 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslCustomer/list',
+ queryById = '/xslmes/mesXslCustomer/queryById',
+ save = '/xslmes/mesXslCustomer/add',
+ edit = '/xslmes/mesXslCustomer/edit',
+ updateStatus = '/xslmes/mesXslCustomer/updateStatus',
+ deleteOne = '/xslmes/mesXslCustomer/delete',
+ deleteBatch = '/xslmes/mesXslCustomer/deleteBatch',
+ importExcel = '/xslmes/mesXslCustomer/importExcel',
+ exportXls = '/xslmes/mesXslCustomer/exportXls',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const queryById = (params: { id: string }) => defHttp.get({ url: Api.queryById, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 启用/停用:status 0 启用 1 停用(与供应商管理 MesXslSupplier.api.updateStatus 一致) */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.data.ts
new file mode 100644
index 0000000..6e011e3
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomer.data.ts
@@ -0,0 +1,105 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '客户编码', align: 'center', dataIndex: 'customerCode', width: 140 },
+ { title: '客户名称', align: 'center', dataIndex: 'customerName', width: 180 },
+ { title: '客户简称', align: 'center', dataIndex: 'customerShortName', width: 120 },
+ { title: '客户区域', align: 'center', dataIndex: 'customerRegion_dictText', width: 100 },
+ { title: 'ERP编码', align: 'center', dataIndex: 'erpCode', width: 140 },
+ // 库表 status + 字典 xslmes_customer_status 翻译(后端 DictAspect 填充 status_dictText)
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 100 },
+ { title: '客户描述', align: 'center', dataIndex: 'customerDesc', width: 200, ellipsis: true },
+ { title: '创建人', align: 'center', dataIndex: 'createBy', width: 100 },
+ {
+ title: '创建时间',
+ align: 'center',
+ dataIndex: 'createTime',
+ width: 165,
+ customRender: ({ text }) => (!text ? '' : String(text).length > 19 ? String(text).substring(0, 19) : text),
+ },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '客户编码', field: 'customerCode', component: 'JInput', colProps: { span: 6 } },
+ { label: '客户名称', field: 'customerName', component: 'JInput', colProps: { span: 6 } },
+ { label: '客户简称', field: 'customerShortName', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '客户区域',
+ field: 'customerRegion',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_customer_region' },
+ colProps: { span: 6 },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_customer_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '客户编码',
+ field: 'customerCode',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入客户编码' },
+ },
+ {
+ label: '客户名称',
+ field: 'customerName',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入客户名称' },
+ },
+ {
+ label: '客户简称',
+ field: 'customerShortName',
+ component: 'Input',
+ componentProps: { placeholder: '请输入客户简称' },
+ },
+ {
+ label: '客户区域',
+ field: 'customerRegion',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_customer_region', placeholder: '请选择客户区域' },
+ },
+ {
+ label: 'ERP编码',
+ field: 'erpCode',
+ component: 'Input',
+ componentProps: { placeholder: '请输入ERP编码' },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_customer_status', placeholder: '请选择状态' },
+ // 默认启用仅在新增弹窗内通过 setFieldsValue 写入,避免编辑时 schema 默认值覆盖接口里的 status
+ },
+ {
+ label: '客户描述',
+ field: 'customerDesc',
+ component: 'InputTextArea',
+ componentProps: { rows: 3, placeholder: '请输入客户描述' },
+ },
+ {
+ label: '租户ID',
+ field: 'tenantId',
+ component: 'InputNumber',
+ componentProps: { placeholder: '租户ID,可空' },
+ },
+];
+
+export const superQuerySchema = {
+ customerCode: { title: '客户编码', order: 0, view: 'text' },
+ customerName: { title: '客户名称', order: 1, view: 'text' },
+ customerShortName: { title: '客户简称', order: 2, view: 'text' },
+ customerRegion: { title: '客户区域', order: 3, view: 'list', dictCode: 'xslmes_customer_region' },
+ status: { title: '状态', order: 4, view: 'list', dictCode: 'xslmes_customer_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomerList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomerList.vue
new file mode 100644
index 0000000..184561c
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/MesXslCustomerList.vue
@@ -0,0 +1,159 @@
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/components/MesXslCustomerModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/components/MesXslCustomerModal.vue
new file mode 100644
index 0000000..cddb116
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslCustomer/components/MesXslCustomerModal.vue
@@ -0,0 +1,91 @@
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.api.ts
new file mode 100644
index 0000000..a23b4fa
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.api.ts
@@ -0,0 +1,56 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslInstrument/list',
+ save = '/xslmes/mesXslInstrument/add',
+ edit = '/xslmes/mesXslInstrument/edit',
+ updateStatus = '/xslmes/mesXslInstrument/updateStatus',
+ deleteOne = '/xslmes/mesXslInstrument/delete',
+ deleteBatch = '/xslmes/mesXslInstrument/deleteBatch',
+ importExcel = '/xslmes/mesXslInstrument/importExcel',
+ exportXls = '/xslmes/mesXslInstrument/exportXls',
+ queryById = '/xslmes/mesXslInstrument/queryById',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const queryById = (params: { id: string }) => defHttp.get({ url: Api.queryById, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 停用/启用:status 0 停用 1 启用 */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.data.ts
new file mode 100644
index 0000000..bffcab7
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrument.data.ts
@@ -0,0 +1,64 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '编号/条码', align: 'center', dataIndex: 'barcode', width: 160 },
+ { title: '规格型号', align: 'center', dataIndex: 'specModel_dictText', width: 140, ellipsis: true },
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 90 },
+ { title: '备注', align: 'center', dataIndex: 'remark', width: 200, ellipsis: true },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '编号/条码', field: 'barcode', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '规格型号',
+ field: 'specModel',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_instrument_spec' },
+ colProps: { span: 6 },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_instrument_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '编号/条码',
+ field: 'barcode',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入编号或条码' },
+ },
+ {
+ label: '规格型号',
+ field: 'specModel',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_instrument_spec', placeholder: '请选择规格型号' },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_instrument_status', placeholder: '请选择状态' },
+ defaultValue: '0',
+ },
+ {
+ label: '备注',
+ field: 'remark',
+ component: 'InputTextArea',
+ componentProps: { placeholder: '请输入备注', rows: 3 },
+ },
+];
+
+export const superQuerySchema = {
+ barcode: { title: '编号/条码', order: 0, view: 'text' },
+ specModel: { title: '规格型号', order: 1, view: 'list', dictCode: 'xslmes_instrument_spec' },
+ status: { title: '状态', order: 2, view: 'list', dictCode: 'xslmes_instrument_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrumentList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrumentList.vue
new file mode 100644
index 0000000..cd375bf
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/MesXslInstrumentList.vue
@@ -0,0 +1,156 @@
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/components/MesXslInstrumentModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/components/MesXslInstrumentModal.vue
new file mode 100644
index 0000000..a43ea18
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslInstrument/components/MesXslInstrumentModal.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.api.ts
new file mode 100644
index 0000000..2f6b4e0
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.api.ts
@@ -0,0 +1,56 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslSupplier/list',
+ save = '/xslmes/mesXslSupplier/add',
+ edit = '/xslmes/mesXslSupplier/edit',
+ updateStatus = '/xslmes/mesXslSupplier/updateStatus',
+ deleteOne = '/xslmes/mesXslSupplier/delete',
+ deleteBatch = '/xslmes/mesXslSupplier/deleteBatch',
+ importExcel = '/xslmes/mesXslSupplier/importExcel',
+ exportXls = '/xslmes/mesXslSupplier/exportXls',
+ queryById = '/xslmes/mesXslSupplier/queryById',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const queryById = (params: { id: string }) => defHttp.get({ url: Api.queryById, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 停用/启用:status 0 停用 1 启用 */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.data.ts
new file mode 100644
index 0000000..07f79b4
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplier.data.ts
@@ -0,0 +1,74 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '编码', align: 'center', dataIndex: 'supplierCode', width: 120 },
+ { title: '名称', align: 'center', dataIndex: 'supplierName', width: 160 },
+ { title: '简称', align: 'center', dataIndex: 'supplierShortName', width: 120 },
+ { title: 'ERP编码', align: 'center', dataIndex: 'erpCode', width: 120 },
+ { title: '备注', align: 'center', dataIndex: 'remark', width: 180, ellipsis: true },
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 90 },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '编码', field: 'supplierCode', component: 'JInput', colProps: { span: 6 } },
+ { label: '名称', field: 'supplierName', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_supplier_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '编码',
+ field: 'supplierCode',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入编码' },
+ },
+ {
+ label: '名称',
+ field: 'supplierName',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入名称' },
+ },
+ {
+ label: '简称',
+ field: 'supplierShortName',
+ component: 'Input',
+ componentProps: { placeholder: '请输入简称' },
+ },
+ {
+ label: 'ERP编码',
+ field: 'erpCode',
+ component: 'Input',
+ componentProps: { placeholder: '请输入ERP编码' },
+ },
+ {
+ label: '备注',
+ field: 'remark',
+ component: 'InputTextArea',
+ componentProps: { placeholder: '请输入备注', rows: 3 },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_supplier_status', placeholder: '请选择状态' },
+ defaultValue: '0',
+ },
+];
+
+export const superQuerySchema = {
+ supplierCode: { title: '编码', order: 0, view: 'text' },
+ supplierName: { title: '名称', order: 1, view: 'text' },
+ supplierShortName: { title: '简称', order: 2, view: 'text' },
+ status: { title: '状态', order: 3, view: 'list', dictCode: 'xslmes_supplier_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplierList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplierList.vue
new file mode 100644
index 0000000..7ea13c7
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/MesXslSupplierList.vue
@@ -0,0 +1,156 @@
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/components/MesXslSupplierModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/components/MesXslSupplierModal.vue
new file mode 100644
index 0000000..38c1d56
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslSupplier/components/MesXslSupplierModal.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.api.ts
new file mode 100644
index 0000000..d206922
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.api.ts
@@ -0,0 +1,56 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslUnit/list',
+ save = '/xslmes/mesXslUnit/add',
+ edit = '/xslmes/mesXslUnit/edit',
+ updateStatus = '/xslmes/mesXslUnit/updateStatus',
+ deleteOne = '/xslmes/mesXslUnit/delete',
+ deleteBatch = '/xslmes/mesXslUnit/deleteBatch',
+ importExcel = '/xslmes/mesXslUnit/importExcel',
+ exportXls = '/xslmes/mesXslUnit/exportXls',
+ queryById = '/xslmes/mesXslUnit/queryById',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const queryById = (params: { id: string }) => defHttp.get({ url: Api.queryById, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 停用/启用:status 0 停用 1 启用 */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.data.ts
new file mode 100644
index 0000000..2872d10
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnit.data.ts
@@ -0,0 +1,83 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '编码', align: 'center', dataIndex: 'unitCode', width: 120 },
+ { title: '名称', align: 'center', dataIndex: 'unitName', width: 140 },
+ { title: 'ERP编码', align: 'center', dataIndex: 'erpCode', width: 120 },
+ { title: '所属分类', align: 'center', dataIndex: 'categoryId_dictText', width: 140, ellipsis: true },
+ { title: '描述', align: 'center', dataIndex: 'unitDesc', width: 200, ellipsis: true },
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 90 },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '编码', field: 'unitCode', component: 'JInput', colProps: { span: 6 } },
+ { label: '名称', field: 'unitName', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_unit_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '编码',
+ field: 'unitCode',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入编码' },
+ },
+ {
+ label: '名称',
+ field: 'unitName',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入名称' },
+ },
+ {
+ label: 'ERP编码',
+ field: 'erpCode',
+ component: 'Input',
+ componentProps: { placeholder: '请输入ERP编码' },
+ },
+ {
+ label: '所属分类',
+ field: 'categoryId',
+ required: true,
+ component: 'JCategorySelect',
+ componentProps: {
+ pcode: 'XSLMES_UNIT',
+ placeholder: '请选择所属分类(分类字典)',
+ },
+ },
+ {
+ label: '描述',
+ field: 'unitDesc',
+ component: 'InputTextArea',
+ componentProps: { rows: 3, placeholder: '请输入描述' },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_unit_status', placeholder: '请选择状态' },
+ defaultValue: '0',
+ },
+ {
+ label: '租户ID',
+ field: 'tenantId',
+ component: 'InputNumber',
+ componentProps: { placeholder: '租户ID,可空' },
+ },
+];
+
+export const superQuerySchema = {
+ unitCode: { title: '编码', order: 0, view: 'text' },
+ unitName: { title: '名称', order: 1, view: 'text' },
+ status: { title: '状态', order: 2, view: 'list', dictCode: 'xslmes_unit_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue
new file mode 100644
index 0000000..47fcfff
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitList.vue
@@ -0,0 +1,618 @@
+
+
+
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.api.ts
new file mode 100644
index 0000000..a7ec441
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.api.ts
@@ -0,0 +1,24 @@
+import { defHttp } from '/@/utils/http/axios';
+import type { Recordable } from '/@/types/global';
+
+/** 单位分类字典根编码(与 Flyway / 后端一致) */
+export const UNIT_CATEGORY_ROOT_CODE = 'XSLMES_UNIT';
+
+export function fetchUnitCategoryRoot() {
+ return defHttp.get({
+ url: '/sys/category/loadOne',
+ params: { field: 'code', val: UNIT_CATEGORY_ROOT_CODE },
+ });
+}
+
+export function saveUnitSysCategory(data: Recordable) {
+ return defHttp.post({ url: '/sys/category/add', data });
+}
+
+export function editUnitSysCategory(data: Recordable) {
+ return defHttp.post({ url: '/sys/category/edit', data });
+}
+
+export function deleteUnitSysCategory(id: string) {
+ return defHttp.delete({ url: '/sys/category/delete', params: { id } }, { joinParamsToUrl: true });
+}
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.data.ts
new file mode 100644
index 0000000..c0d2543
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/MesXslUnitSysCategory.data.ts
@@ -0,0 +1,36 @@
+import { FormSchema } from '/@/components/Table';
+
+/** 单位分类(分类字典)维护表单 */
+export const unitSysCategoryFormSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '父级分类',
+ field: 'pid',
+ required: true,
+ component: 'TreeSelect',
+ componentProps: {
+ fieldNames: { label: 'title', value: 'key' },
+ treeData: [],
+ showSearch: true,
+ allowClear: false,
+ treeDefaultExpandAll: true,
+ dropdownStyle: { maxHeight: '50vh' },
+ getPopupContainer: () => document.body,
+ },
+ dynamicDisabled: ({ values }) => !!values.id,
+ },
+ {
+ label: '分类编码',
+ field: 'code',
+ component: 'Input',
+ componentProps: { readonly: true },
+ ifShow: ({ values }) => !!values.id,
+ },
+ {
+ label: '分类名称',
+ field: 'name',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入分类名称' },
+ },
+];
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitModal.vue
new file mode 100644
index 0000000..e424a17
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitModal.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitSysCategoryModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitSysCategoryModal.vue
new file mode 100644
index 0000000..1939a47
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslUnit/components/MesXslUnitSysCategoryModal.vue
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.api.ts
new file mode 100644
index 0000000..8899007
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.api.ts
@@ -0,0 +1,53 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslVehicle/list',
+ save = '/xslmes/mesXslVehicle/add',
+ edit = '/xslmes/mesXslVehicle/edit',
+ updateStatus = '/xslmes/mesXslVehicle/updateStatus',
+ deleteOne = '/xslmes/mesXslVehicle/delete',
+ deleteBatch = '/xslmes/mesXslVehicle/deleteBatch',
+ importExcel = '/xslmes/mesXslVehicle/importExcel',
+ exportXls = '/xslmes/mesXslVehicle/exportXls',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 停用/启用:status 0 停用 1 启用 */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.data.ts
new file mode 100644
index 0000000..bfc583f
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicle.data.ts
@@ -0,0 +1,137 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '车牌号', align: 'center', dataIndex: 'plateNumber', width: 120 },
+ { title: '车辆归属', align: 'center', dataIndex: 'vehicleBelong_dictText', width: 100 },
+ { title: '车辆皮重(KG)', align: 'center', dataIndex: 'tareWeightKg', width: 110 },
+ { title: '装载量', align: 'center', dataIndex: 'loadCapacity', width: 100 },
+ { title: '单位ID', align: 'center', dataIndex: 'unitId', width: 200, ellipsis: true, defaultHidden: true },
+ { title: '单位', align: 'center', dataIndex: 'loadUnit', width: 100 },
+ { title: '客户简称', align: 'center', dataIndex: 'customerShortName', width: 160, ellipsis: true },
+ { title: '客户ID', align: 'center', dataIndex: 'customerIds', width: 180, ellipsis: true, defaultHidden: true },
+ { title: '供应商ID', align: 'center', dataIndex: 'supplierId', width: 200, ellipsis: true, defaultHidden: true },
+ { title: '供应商简称', align: 'center', dataIndex: 'supplierShortName', width: 140, ellipsis: true },
+ { title: '司机', align: 'center', dataIndex: 'driverName', width: 90 },
+ { title: '联系电话', align: 'center', dataIndex: 'driverPhone', width: 120 },
+ { title: '车长', align: 'center', dataIndex: 'vehicleLength', width: 80 },
+ { title: '车宽', align: 'center', dataIndex: 'vehicleWidth', width: 80 },
+ { title: '车高', align: 'center', dataIndex: 'vehicleHeight', width: 80 },
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 90 },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '车牌号', field: 'plateNumber', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '车辆归属',
+ field: 'vehicleBelong',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_vehicle_belong' },
+ colProps: { span: 6 },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_vehicle_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '车牌号',
+ field: 'plateNumber',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入车牌号' },
+ },
+ {
+ label: '车辆归属',
+ field: 'vehicleBelong',
+ required: true,
+ component: 'Input',
+ slot: 'vehicleBelongPicker',
+ },
+ {
+ label: '车辆皮重(KG)',
+ field: 'tareWeightKg',
+ component: 'InputNumber',
+ componentProps: { min: 0, placeholder: '车辆皮重', style: { width: '100%' } },
+ },
+ {
+ label: '装载量',
+ field: 'loadCapacity',
+ component: 'InputNumber',
+ componentProps: { min: 0, placeholder: '装载量', style: { width: '100%' } },
+ },
+ { label: '单位ID', field: 'unitId', component: 'Input', show: false },
+ {
+ label: '单位',
+ field: 'loadUnit',
+ component: 'Input',
+ slot: 'unitPicker',
+ },
+ { label: '客户ID', field: 'customerIds', component: 'Input', show: false },
+ {
+ label: '客户简称',
+ field: 'customerShortName',
+ component: 'Input',
+ slot: 'customerPicker',
+ ifShow: ({ values }) => values.vehicleBelong === '1',
+ },
+ { label: '供应商ID', field: 'supplierId', component: 'Input', show: false },
+ { label: '供应商名称', field: 'supplierName', component: 'Input', show: false },
+ {
+ label: '供应商简称',
+ field: 'supplierShortName',
+ component: 'Input',
+ slot: 'supplierPicker',
+ ifShow: ({ values }) => values.vehicleBelong === '2',
+ },
+ {
+ label: '车长',
+ field: 'vehicleLength',
+ component: 'InputNumber',
+ componentProps: { min: 0, placeholder: '车长', style: { width: '100%' } },
+ },
+ {
+ label: '车宽',
+ field: 'vehicleWidth',
+ component: 'InputNumber',
+ componentProps: { min: 0, placeholder: '车宽', style: { width: '100%' } },
+ },
+ {
+ label: '车高',
+ field: 'vehicleHeight',
+ component: 'InputNumber',
+ componentProps: { min: 0, placeholder: '车高', style: { width: '100%' } },
+ },
+ {
+ label: '司机',
+ field: 'driverName',
+ component: 'Input',
+ componentProps: { placeholder: '请输入司机姓名' },
+ },
+ {
+ label: '联系电话',
+ field: 'driverPhone',
+ component: 'Input',
+ componentProps: { placeholder: '请输入联系电话' },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_vehicle_status', placeholder: '请选择状态' },
+ defaultValue: '0',
+ },
+];
+
+export const superQuerySchema = {
+ plateNumber: { title: '车牌号', order: 0, view: 'text' },
+ vehicleBelong: { title: '车辆归属', order: 1, view: 'list', dictCode: 'xslmes_vehicle_belong' },
+ status: { title: '状态', order: 2, view: 'list', dictCode: 'xslmes_vehicle_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicleList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicleList.vue
new file mode 100644
index 0000000..5d2f963
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/MesXslVehicleList.vue
@@ -0,0 +1,159 @@
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslCustomerSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslCustomerSelectModal.vue
new file mode 100644
index 0000000..e0b9790
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslCustomerSelectModal.vue
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslSupplierSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslSupplierSelectModal.vue
new file mode 100644
index 0000000..7f48eea
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslSupplierSelectModal.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslUnitSelectModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslUnitSelectModal.vue
new file mode 100644
index 0000000..50e1cba
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslUnitSelectModal.vue
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslVehicleModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslVehicleModal.vue
new file mode 100644
index 0000000..42f96b2
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslVehicle/components/MesXslVehicleModal.vue
@@ -0,0 +1,496 @@
+
+
+
+
+
+
+
+ onVehicleBelongChange(model, v)"
+ />
+
+
+
+
+
+
+
+
+ 选择单位
+
+ 清除
+
+
+
+
+
+
+
+
+
+
+
+ 选择客户
+
+ 清除
+
+
+
+
+
+
+
+
+
+
+
+ 选择供应商
+
+ 清除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.api.ts
new file mode 100644
index 0000000..4cc66f2
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.api.ts
@@ -0,0 +1,56 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+ list = '/xslmes/mesXslWarehouse/list',
+ queryById = '/xslmes/mesXslWarehouse/queryById',
+ save = '/xslmes/mesXslWarehouse/add',
+ edit = '/xslmes/mesXslWarehouse/edit',
+ updateStatus = '/xslmes/mesXslWarehouse/updateStatus',
+ deleteOne = '/xslmes/mesXslWarehouse/delete',
+ deleteBatch = '/xslmes/mesXslWarehouse/deleteBatch',
+ importExcel = '/xslmes/mesXslWarehouse/importExcel',
+ exportXls = '/xslmes/mesXslWarehouse/exportXls',
+}
+
+export const getExportUrl = Api.exportXls;
+export const getImportUrl = Api.importExcel;
+
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const queryById = (params: { id: string }) => defHttp.get({ url: Api.queryById, params });
+
+export const deleteOne = (params, handleSuccess) => {
+ return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+};
+
+export const batchDelete = (params, handleSuccess) => {
+ createConfirm({
+ iconType: 'warning',
+ title: '确认删除',
+ content: '是否删除选中数据',
+ okText: '确认',
+ cancelText: '取消',
+ onOk: () => {
+ return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess();
+ });
+ },
+ });
+};
+
+export const saveOrUpdate = (params, isUpdate) => {
+ const url = isUpdate ? Api.edit : Api.save;
+ return defHttp.post({ url, params });
+};
+
+/** 启用/停用:status 0 启用 1 停用(字典 xslmes_unit_status) */
+export const updateStatus = (params: { id: string; status: string }, handleSuccess?: () => void) => {
+ return defHttp.post({ url: Api.updateStatus, params }, { joinParamsToUrl: true }).then(() => {
+ handleSuccess?.();
+ });
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.data.ts
new file mode 100644
index 0000000..c167391
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouse.data.ts
@@ -0,0 +1,111 @@
+import { BasicColumn, FormSchema } from '/@/components/Table';
+
+/** 分类字典 code:二楼-客户库(与后端 MesXslWarehouseCategory 一致) */
+export const WH_CATEGORY_CUSTOMER_CODE = 'XSLMES_WH_F2_KH';
+/** 分类字典 code:二楼-供应商库 */
+export const WH_CATEGORY_SUPPLIER_CODE = 'XSLMES_WH_F2_GYS';
+
+export const columns: BasicColumn[] = [
+ { title: 'ID', align: 'center', dataIndex: 'id', width: 280, ellipsis: true, defaultHidden: true },
+ { title: '仓库编码', align: 'center', dataIndex: 'warehouseCode', width: 120 },
+ { title: '仓库名称', align: 'center', dataIndex: 'warehouseName', width: 160 },
+ { title: '仓库分类', align: 'center', dataIndex: 'warehouseCategory_dictText', width: 120 },
+ { title: 'ERP编码', align: 'center', dataIndex: 'erpCode', width: 120 },
+ { title: '客户简称', align: 'center', dataIndex: 'customerShortName', width: 120, ellipsis: true },
+ { title: '供应商简称', align: 'center', dataIndex: 'supplierShortName', width: 120 },
+ { title: '状态', align: 'center', dataIndex: 'status_dictText', width: 90 },
+ { title: '创建人', align: 'center', dataIndex: 'createBy', width: 100 },
+ {
+ title: '创建时间',
+ align: 'center',
+ dataIndex: 'createTime',
+ width: 165,
+ customRender: ({ text }) => (!text ? '' : String(text).length > 19 ? String(text).substring(0, 19) : text),
+ },
+ { title: '租户ID', align: 'center', dataIndex: 'tenantId', width: 90, defaultHidden: true },
+];
+
+export const searchFormSchema: FormSchema[] = [
+ { label: '仓库编码', field: 'warehouseCode', component: 'JInput', colProps: { span: 6 } },
+ { label: '仓库名称', field: 'warehouseName', component: 'JInput', colProps: { span: 6 } },
+ {
+ label: '仓库分类',
+ field: 'warehouseCategory',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'sys_category,name,id' },
+ colProps: { span: 6 },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_unit_status' },
+ colProps: { span: 6 },
+ },
+];
+
+export const formSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '仓库编码',
+ field: 'warehouseCode',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入仓库编码' },
+ },
+ {
+ label: '仓库名称',
+ field: 'warehouseName',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入仓库名称' },
+ },
+ {
+ label: '仓库分类',
+ field: 'warehouseCategory',
+ required: true,
+ component: 'Input',
+ slot: 'warehouseCategoryField',
+ },
+ {
+ label: 'ERP编码',
+ field: 'erpCode',
+ component: 'Input',
+ componentProps: { placeholder: '请输入ERP编码' },
+ },
+ {
+ label: '状态',
+ field: 'status',
+ component: 'JDictSelectTag',
+ componentProps: { dictCode: 'xslmes_unit_status', placeholder: '请选择状态' },
+ },
+ { label: '客户ID', field: 'customerId', component: 'Input', show: false },
+ {
+ label: '客户简称',
+ field: 'customerShortName',
+ component: 'Input',
+ slot: 'customerPicker',
+ ifShow: false,
+ },
+ { label: '供应商ID', field: 'supplierId', component: 'Input', show: false },
+ {
+ label: '供应商简称',
+ field: 'supplierShortName',
+ component: 'Input',
+ slot: 'supplierPicker',
+ ifShow: false,
+ },
+ {
+ label: '租户ID',
+ field: 'tenantId',
+ component: 'InputNumber',
+ componentProps: { placeholder: '租户ID,可空', style: { width: '100%' } },
+ },
+];
+
+export const superQuerySchema = {
+ warehouseCode: { title: '仓库编码', order: 0, view: 'text' },
+ warehouseName: { title: '仓库名称', order: 1, view: 'text' },
+ warehouseCategory: { title: '仓库分类', order: 2, view: 'list', dictCode: 'sys_category,name,id' },
+ status: { title: '状态', order: 3, view: 'list', dictCode: 'xslmes_unit_status' },
+};
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue
new file mode 100644
index 0000000..e9807ff
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseList.vue
@@ -0,0 +1,651 @@
+
+
+
+
+
+
+
+ 新增
+ 导出
+ 导入
+
+
+
+
+
+ 删除
+
+
+
+
+ 批量操作
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.api.ts b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.api.ts
new file mode 100644
index 0000000..f8c51c6
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.api.ts
@@ -0,0 +1,25 @@
+import { defHttp } from '/@/utils/http/axios';
+import type { Recordable } from '/@/types/global';
+
+/** 仓库分类字典根编码(与 Flyway / 后端一致) */
+export const WAREHOUSE_CATEGORY_ROOT_CODE = 'XSLMES_WH';
+
+/** 按编码查询分类(用于取根节点 id) */
+export function fetchWarehouseCategoryRoot() {
+ return defHttp.get({
+ url: '/sys/category/loadOne',
+ params: { field: 'code', val: WAREHOUSE_CATEGORY_ROOT_CODE },
+ });
+}
+
+export function saveWarehouseSysCategory(data: Recordable) {
+ return defHttp.post({ url: '/sys/category/add', data });
+}
+
+export function editWarehouseSysCategory(data: Recordable) {
+ return defHttp.post({ url: '/sys/category/edit', data });
+}
+
+export function deleteWarehouseSysCategory(id: string) {
+ return defHttp.delete({ url: '/sys/category/delete', params: { id } }, { joinParamsToUrl: true });
+}
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.data.ts b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.data.ts
new file mode 100644
index 0000000..fef0546
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/MesXslWarehouseSysCategory.data.ts
@@ -0,0 +1,36 @@
+import { FormSchema } from '/@/components/Table';
+
+/** 分类字典维护表单(仅 MES 仓库分类子树) */
+export const warehouseSysCategoryFormSchema: FormSchema[] = [
+ { label: '', field: 'id', component: 'Input', show: false },
+ {
+ label: '父级分类',
+ field: 'pid',
+ required: true,
+ component: 'TreeSelect',
+ componentProps: {
+ fieldNames: { label: 'title', value: 'key' },
+ treeData: [],
+ showSearch: true,
+ allowClear: false,
+ treeDefaultExpandAll: true,
+ dropdownStyle: { maxHeight: '50vh' },
+ getPopupContainer: () => document.body,
+ },
+ dynamicDisabled: ({ values }) => !!values.id,
+ },
+ {
+ label: '分类编码',
+ field: 'code',
+ component: 'Input',
+ componentProps: { readonly: true },
+ ifShow: ({ values }) => !!values.id,
+ },
+ {
+ label: '分类名称',
+ field: 'name',
+ required: true,
+ component: 'Input',
+ componentProps: { placeholder: '请输入分类名称' },
+ },
+];
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseModal.vue
new file mode 100644
index 0000000..dc6f3ed
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseModal.vue
@@ -0,0 +1,472 @@
+
+
+
+
+
+
+
+
+ onWarehouseCategoryChange(model, _v)"
+
+ />
+
+
+
+
+
+
+
+
+
+ 选择客户
+
+ 清除
+
+
+
+
+
+
+
+
+
+
+
+ 选择供应商
+
+ 清除
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseSysCategoryModal.vue b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseSysCategoryModal.vue
new file mode 100644
index 0000000..e6c0864
--- /dev/null
+++ b/jeecgboot-vue3/src/views/xslmes/mesXslWarehouse/components/MesXslWarehouseSysCategoryModal.vue
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
diff --git a/qhmes.code-workspace b/qhmes.code-workspace
new file mode 100644
index 0000000..6bf67e9
--- /dev/null
+++ b/qhmes.code-workspace
@@ -0,0 +1,12 @@
+{
+ "folders": [
+ {
+ "path": "jeecg-boot",
+ "name": "后端 (jeecg-boot)"
+ },
+ {
+ "path": "jeecgboot-vue3",
+ "name": "前端 (jeecgboot-vue3)"
+ }
+ ]
+}