From c6e203d8e80c9cd8f74c79498662fa20d223ff56 Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期二, 08 四月 2025 08:14:28 +0800
Subject: [PATCH] 知识库,备件

---
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareType.java                                                            |   71 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java              |    3 
 eims-ui/apps/web-antd/src/views/eims/spare-type/index.vue                                                                                      |  170 +
 eims-ui/apps/web-antd/src/api/eims/spare-inout/index.ts                                                                                        |   61 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareInout.java                                                           |   70 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFaultKnowService.java                                                   |   68 
 eims-ui/apps/web-antd/src/views/eims/fault-know/data.tsx                                                                                       |  205 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareVo.java                                                           |  147 +
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareInoutMapper.xml                                                             |    7 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFaultKnowServiceImpl.java                                           |  191 +
 eims-ui/apps/web-antd/src/api/eims/spare-type/model.d.ts                                                                                       |   66 
 eims-ui/apps/web-antd/src/views/eims/spare/data.tsx                                                                                            |  282 ++
 eims-ui/apps/web-antd/src/api/eims/fault-know/model.d.ts                                                                                       |   51 
 eims-ui/apps/web-antd/src/views/eims/fault-know/equ-type-tree.vue                                                                              |  121 +
 eims-ui/apps/web-antd/src/views/eims/spare/index.vue                                                                                           |  217 ++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareInoutService.java                                                  |   68 
 eims-ui/apps/web-antd/src/views/eims/spare-type/spare-type-drawer.vue                                                                          |  132 +
 eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue                                                                                        |  237 ++
 eims-ui/apps/web-antd/src/api/eims/spare-type/index.ts                                                                                         |   69 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/SpareTypeService.java                                        |   11 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/InspectPlanToRecordJob.java                                                      |  124 +
 eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue                                                                              |  155 +
 eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue                                                                            |  155 +
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/SpareTypeNameTranslationImpl.java            |   30 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java                            |    8 
 eims-ui/apps/web-antd/src/views/eims/spare/spare-type-tree.vue                                                                                 |  121 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareTypeVo.java                                                       |   88 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareMapper.java                                                          |   15 
 eims-ui/apps/web-antd/src/api/eims/spare/index.ts                                                                                              |   61 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareTypeController.java                                              |  126 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareTypeBo.java                                                       |   74 
 eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts                                                                                      |   41 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpare.java                                                                |  114 +
 eims-ui/apps/web-antd/src/api/eims/fault-know/index.ts                                                                                         |   61 
 eims-ui/apps/web-antd/src/views/eims/fault-know/fault-know-drawer.vue                                                                          |  114 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFaultKnowBo.java                                                       |   94 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareInoutServiceImpl.java                                          |  135 +
 eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java                                                    |   20 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFaultKnowMapper.java                                                      |   23 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareTypeService.java                                                   |   76 
 eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue                                                                          |    2 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareTypeMapper.xml                                                              |    7 
 eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports |    1 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareMapper.xml                                                                  |    7 
 eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts                                                                                  |   10 
 eims-ui/apps/web-antd/src/views/eims/spare-type/data.tsx                                                                                       |  196 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquVo.java                                                             |    2 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareInoutController.java                                             |  105 
 eims-ui/apps/web-antd/src/views/eims/fixture/index.vue                                                                                         |    8 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFaultKnow.java                                                            |   76 
 eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx                                                                                        |  156 +
 eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx                                                                                         |  156 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareService.java                                                       |   68 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareController.java                                                  |  105 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareBo.java                                                           |  117 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareTypeMapper.java                                                      |   15 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFaultKnowController.java                                              |  105 
 eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java                                           |    2 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareServiceImpl.java                                               |  135 +
 eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue                                                                                       |  237 ++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareInoutBo.java                                                      |   73 
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java                                          |    9 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareInoutVo.java                                                      |   91 
 eims-ui/apps/web-antd/src/api/eims/spare/model.d.ts                                                                                            |   90 
 eims-ui/apps/web-antd/src/views/eims/insp-plan/data.tsx                                                                                        |    6 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareTypeServiceImpl.java                                           |  188 +
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFaultKnowMapper.xml                                                              |   15 
 eims-ui/apps/web-antd/src/views/eims/fault-know/index.vue                                                                                      |  194 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareInoutMapper.java                                                     |   15 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFaultKnowVo.java                                                       |  100 
 eims-ui/apps/web-antd/src/views/eims/spare/spare-drawer.vue                                                                                    |  149 +
 71 files changed, 6,306 insertions(+), 16 deletions(-)

diff --git a/eims-ui/apps/web-antd/src/api/eims/fault-know/index.ts b/eims-ui/apps/web-antd/src/api/eims/fault-know/index.ts
new file mode 100644
index 0000000..86d853d
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fault-know/index.ts
@@ -0,0 +1,61 @@
+import type { FaultKnowVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  faultKnowExport = '/eims/faultKnow/export',
+  faultKnowList = '/eims/faultKnow/list',
+  root = '/eims/faultKnow'
+}
+
+/**
+ * 鏌ヨ鏁呴殰鐭ヨ瘑鍒楄〃
+ * @param params
+ * @returns {*}
+ */
+
+export function listFaultKnow(params?: any) {
+  return requestClient.get<FaultKnowVO[]>(Api.faultKnowList, { params });
+}
+
+/**
+ * 鏌ヨ鏁呴殰鐭ヨ瘑璇︾粏
+ * @param faultKnowId
+ */
+export function getFaultKnow(faultKnowId: ID) {
+  return requestClient.get<FaultKnowVO>(`${Api.root}/${faultKnowId}`);
+}
+
+/**
+ * 鏂板鏁呴殰鐭ヨ瘑
+ * @param data
+ */
+export function addFaultKnow(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼鏁呴殰鐭ヨ瘑
+ * @param data
+ */
+export function updateFaultKnow(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎鏁呴殰鐭ヨ瘑
+ * @param faultKnowId
+ */
+export function delFaultKnow(faultKnowId: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${faultKnowId}`);
+}
+/**
+ * 瀵煎嚭
+ * @param
+ */
+export function faultKnowExport(data: any) {
+  return commonExport(Api.faultKnowExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/fault-know/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/fault-know/model.d.ts
new file mode 100644
index 0000000..5f0fadc
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fault-know/model.d.ts
@@ -0,0 +1,51 @@
+export interface FaultKnowVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 璁惧id
+   */
+  equId: number | string;
+
+  /**
+   * 璁惧绫诲瀷
+   */
+  equType: number;
+
+  /**
+   * 璁惧閮ㄤ綅(瀛楀吀)
+   */
+  equPart: string;
+
+  /**
+   * 鐭ヨ瘑缂栫爜
+   */
+  faultCode: string;
+
+  /**
+   * 鏁呴殰绫诲埆(瀛楀吀)
+   */
+  faultType: string;
+
+  /**
+   * 鏁呴殰鍘熷洜(瀛楀吀)
+   */
+  faultReason: string;
+
+  /**
+   * 鎶ヤ慨鎻忚堪
+   */
+  reqDesc: string;
+
+  /**
+   * 澶勭悊鎺柦
+   */
+  resHandle: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-inout/index.ts b/eims-ui/apps/web-antd/src/api/eims/spare-inout/index.ts
new file mode 100644
index 0000000..ca8ca0b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-inout/index.ts
@@ -0,0 +1,61 @@
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+import type { SpareInoutVO } from '#/api/eims/spare-inout/model';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/eims/spareInout',
+  spareInoutExport = '/eims/spareInout/export',
+  spareInoutList = '/eims/spareInout/list'
+}
+
+/**
+ * 鏌ヨ銆愬浠跺彴璐︺�戝垪琛�
+ * @param query
+ * @returns {*}
+ */
+
+export function listSpareInout(params?: PageQuery) {
+  return requestClient.get<PageResult<SpareInoutVO>>(Api.spareInoutList, { params });
+}
+
+/**
+ * 鏌ヨ銆愬浠跺彴璐︺�戣缁�
+ * @param spareInoutId
+ */
+export function getSpareInout(spareInoutId: any) {
+  return requestClient.get<SpareInoutVO>(`${Api.root}/${spareInoutId}`);
+}
+
+/**
+ * 鏂板銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function addSpareInout(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function updateSpareInout(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎銆愬浠跺彴璐︺��
+ * @param spareInoutIds
+ */
+export function delSpareInout(spareInoutIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${spareInoutIds}`);
+}
+
+/**
+ * 瀵煎嚭銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function spareInoutExport(data: any) {
+  return commonExport(Api.spareInoutExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts
new file mode 100644
index 0000000..ae55af8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts
@@ -0,0 +1,41 @@
+export interface SpareInoutVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 鍗曞彿
+   */
+  orderCode: string;
+
+  /**
+   * 鍗曞彿鏃ユ湡
+   */
+  orderDate: string;
+
+  /**
+   * 缁忓姙浜�
+   */
+  chargeUser: number;
+
+  /**
+   * 宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀
+   */
+  type: string;
+
+  /**
+   * 鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢
+   */
+  partnerName: string;
+
+  /**
+   * 鍏宠仈鍗曞彿锛堝-缁翠慨鍗曪級
+   */
+  associatedOrder: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-type/index.ts b/eims-ui/apps/web-antd/src/api/eims/spare-type/index.ts
new file mode 100644
index 0000000..f9a2f25
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-type/index.ts
@@ -0,0 +1,69 @@
+import type { SpareTypeTree, SpareTypeVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/eims/spareType',
+  spareTypeExport = '/eims/spareType/export',
+  spareTypeList = '/eims/spareType/list',
+  spareTypeTree = '/eims/spareType/tree'
+}
+
+/**
+ * 鏌ヨ澶囦欢绫诲瀷鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export function listSpareType(params?: any) {
+  return requestClient.get<SpareTypeVO[]>(Api.spareTypeList, { params });
+}
+
+/**
+ * 鑾峰彇澶囦欢绫诲瀷鏍�
+ * @returns 閮ㄩ棬鏍戞暟缁�
+ */
+export function getSpareTypeTree() {
+  return requestClient.get<SpareTypeTree[]>(Api.spareTypeTree);
+}
+
+/**
+ * 鏌ヨ澶囦欢绫诲瀷璇︾粏
+ * @param spareTypeId
+ */
+export function getSpareType(spareTypeId: ID) {
+  return requestClient.get<SpareTypeVO>(`${Api.root}/${spareTypeId}`);
+}
+
+/**
+ * 鏂板澶囦欢绫诲瀷
+ * @param data
+ */
+export function addSpareType(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+/**
+ * 淇敼澶囦欢绫诲瀷
+ * @param data
+ */
+export function updateSpareType(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎澶囦欢绫诲瀷
+ * @param spareTypeId
+ */
+export function delSpareType(spareTypeId: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${spareTypeId}`);
+}
+/**
+ * 瀵煎嚭
+ * @param
+ */
+export function spareTypeExport(data: any) {
+  return commonExport(Api.spareTypeExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-type/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/spare-type/model.d.ts
new file mode 100644
index 0000000..f3e3ccd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-type/model.d.ts
@@ -0,0 +1,66 @@
+export interface SpareTypeVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 绫诲瀷鍚嶇О
+   */
+  typeName: string;
+
+  /**
+   * 绫诲瀷缂栫爜
+   */
+  typeCode: string;
+
+  /**
+   * 鐖秈d
+   */
+  parentId: number | string;
+
+  /**
+   * 鏄剧ず椤哄簭
+   */
+  orderNum: number;
+
+  /**
+   * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+   */
+  menuType: string;
+
+  /**
+   * 鑿滃崟鍥炬爣
+   */
+  icon: string;
+
+  /**
+   * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+   */
+  status: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+
+  /**
+   * 瀛愬璞�
+   */
+  children: SpareTypeVO[];
+}
+
+/**
+ * @description: 澶囦欢绫诲瀷鏍�
+ */
+export interface SpareTypeTree {
+  id: number;
+  /**
+   * antd缁勪欢蹇呴』瑕佽繖涓睘鎬� 瀹為檯鏄病鏈夎繖涓睘鎬х殑
+   */
+  key: string;
+  parentId: number;
+  label: string;
+  weight: number;
+  children?: SpareTypeTree[];
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare/index.ts b/eims-ui/apps/web-antd/src/api/eims/spare/index.ts
new file mode 100644
index 0000000..b5886ed
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare/index.ts
@@ -0,0 +1,61 @@
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+import type { SpareVO } from '#/api/eims/spare/model';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/eims/spare',
+  spareExport = '/eims/spare/export',
+  spareList = '/eims/spare/list'
+}
+
+/**
+ * 鏌ヨ銆愬浠跺彴璐︺�戝垪琛�
+ * @param query
+ * @returns {*}
+ */
+
+export function listSpare(params?: PageQuery) {
+  return requestClient.get<PageResult<SpareVO>>(Api.spareList, { params });
+}
+
+/**
+ * 鏌ヨ銆愬浠跺彴璐︺�戣缁�
+ * @param spareId
+ */
+export function getSpare(spareId: any) {
+  return requestClient.get<SpareVO>(`${Api.root}/${spareId}`);
+}
+
+/**
+ * 鏂板銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function addSpare(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function updateSpare(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎銆愬浠跺彴璐︺��
+ * @param spareIds
+ */
+export function delSpare(spareIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${spareIds}`);
+}
+
+/**
+ * 瀵煎嚭銆愬浠跺彴璐︺��
+ * @param data
+ */
+export function spareExport(data: any) {
+  return commonExport(Api.spareExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/spare/model.d.ts
new file mode 100644
index 0000000..8a6071b
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare/model.d.ts
@@ -0,0 +1,90 @@
+export interface SpareVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 绫诲瀷
+   */
+  type: number;
+
+  /**
+   * 澶囦欢鍚嶇О
+   */
+  name: string;
+
+  /**
+   * 澶囦欢缂栫爜
+   */
+  code: string;
+
+  /**
+   * 澶囦欢鍥剧墖
+   */
+  img: number;
+
+  /**
+   * 澶囦欢鍥剧墖Url
+   */
+  imgUrl: string;
+  /**
+   * 鍨嬪彿
+   */
+  modelNo: string;
+
+  /**
+   * 鍒堕�犲晢
+   */
+  madeIn: string;
+
+  /**
+   * 渚涘簲鍟�
+   */
+  supplier: string;
+
+  /**
+   * 璁¢噺鍗曚綅锛堝瓧鍏革級
+   */
+  unit: string;
+
+  /**
+   * 鍙傝�冧环鏍�
+   */
+  referPrice: number;
+
+  /**
+   * 搴撳瓨涓婇檺
+   */
+  upperStock: number;
+
+  /**
+   * 搴撳瓨涓嬮檺
+   */
+  lowerStock: number;
+
+  /**
+   * 瀹為檯搴撳瓨
+   */
+  actualStock: number;
+
+  /**
+   * 搴撳瓨閲戦
+   */
+  stockAmount: number;
+
+  /**
+   * 鏇存崲鍛ㄦ湡
+   */
+  replaceCycle: number;
+
+  /**
+   * 鏇存崲鍛ㄦ湡鍗曚綅锛堝瓧鍏革級
+   */
+  cycleUnit: string;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
diff --git a/eims-ui/apps/web-antd/src/views/eims/fault-know/data.tsx b/eims-ui/apps/web-antd/src/views/eims/fault-know/data.tsx
new file mode 100644
index 0000000..8cc1cef
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fault-know/data.tsx
@@ -0,0 +1,205 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'faultCode',
+    label: '鐭ヨ瘑缂栧彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'equName',
+    label: '璁惧鍚嶇О'
+  },
+  {
+    component: 'Input',
+    fieldName: 'assetNo',
+    label: '璧勪骇缂栧彿'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.EIMS_EQU_PART)
+    },
+    fieldName: 'equPart',
+    label: '璁惧閮ㄤ綅'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.REPAIR_FAULT_TYPE)
+    },
+    fieldName: 'faultType',
+    label: '鏁呴殰绫诲埆'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.EIMS_FAULT_REASON)
+    },
+    fieldName: 'faultReason',
+    label: '鏁呴殰鍘熷洜'
+  },
+  {
+    component: 'Input',
+    fieldName: 'reqDesc',
+    label: '鏁呴殰鎻忚堪'
+  },
+  {
+    component: 'Input',
+    fieldName: 'resHandle',
+    label: '澶勭悊鎺柦'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '鐭ヨ瘑缂栫爜',
+    field: 'faultCode',
+    minWidth: 200
+  },
+  {
+    title: '璁惧鍚嶇О',
+    field: 'equName',
+    minWidth: 140,
+    fixed: 'left',
+    slots: { default: 'equName' }
+  },
+  {
+    title: '璧勪骇缂栧彿',
+    field: 'assetNo',
+    sortable: true,
+    minWidth: 140,
+    fixed: 'left'
+  },
+  {
+    title: '璁惧绫诲瀷',
+    field: 'equTypeName',
+    minWidth: 140
+  },
+  {
+    title: '璁惧閮ㄤ綅',
+    field: 'equPart',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (row.equPart === null || row.equPart === '') {
+          return '';
+        }
+        return renderDict(row.equPart, DictEnum.EIMS_EQU_PART);
+      }
+    },
+    minWidth: 120
+  },
+  {
+    title: '鏁呴殰绫诲埆',
+    field: 'faultType',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (row.faultType === null || row.faultType === '') {
+          return '';
+        }
+        return renderDict(row.faultType, DictEnum.REPAIR_FAULT_TYPE);
+      }
+    },
+    minWidth: 120
+  },
+  {
+    title: '鏁呴殰鍘熷洜',
+    field: 'faultReason',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (row.faultReason === null || row.faultReason === '') {
+          return '';
+        }
+        return renderDict(row.faultReason, DictEnum.EIMS_FAULT_REASON);
+      }
+    },
+    minWidth: 120
+  },
+  {
+    title: '鎶ヤ慨鎻忚堪',
+    field: 'reqDesc',
+    minWidth: 300
+  },
+  {
+    title: '澶勭悊鎺柦',
+    field: 'resHandle',
+    minWidth: 300
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'equId'
+  },
+  {
+    component: 'Input',
+    fieldName: 'faultCode',
+    label: '鐭ヨ瘑缂栫爜',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'equName',
+    label: '璁惧鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.EIMS_EQU_PART)
+    },
+    fieldName: 'equPart',
+    label: '璁惧閮ㄤ綅'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.REPAIR_FAULT_TYPE)
+    },
+    fieldName: 'faultType',
+    label: '鏁呴殰绫诲埆'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.EIMS_FAULT_REASON)
+    },
+    fieldName: 'faultReason',
+    label: '鏁呴殰鍘熷洜'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'reqDesc',
+    label: '鎶ヤ慨鎻忚堪'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'resHandle',
+    label: '澶勭悊鎺柦'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/fault-know/equ-type-tree.vue b/eims-ui/apps/web-antd/src/views/eims/fault-know/equ-type-tree.vue
new file mode 100644
index 0000000..8183ed3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fault-know/equ-type-tree.vue
@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import type { DeptTree } from '#/api/system/user/model';
+
+import { onMounted, type PropType, ref } from 'vue';
+
+import { SyncOutlined } from '@ant-design/icons-vue';
+import { Empty, InputSearch, Skeleton, Tree } from 'ant-design-vue';
+
+import { getEquTypeTree } from '#/api/eims/equ-type';
+
+defineOptions({ inheritAttrs: false });
+
+const emit = defineEmits<{
+  /**
+   * 鐐瑰嚮鍒锋柊鎸夐挳鐨勪簨浠�
+   */
+  reload: [];
+  /**
+   * 鐐瑰嚮鑺傜偣鐨勪簨浠�
+   */
+  select: [];
+}>();
+
+const selectDeptId = defineModel('selectDeptId', {
+  required: true,
+  type: Array as PropType<string[]>,
+});
+
+const searchValue = defineModel('searchValue', {
+  type: String,
+  default: '',
+});
+
+/** 閮ㄩ棬鏁版嵁婧� */
+type DeptTreeArray = DeptTree[];
+const deptTreeArray = ref<DeptTreeArray>([]);
+/** 楠ㄦ灦灞忓姞杞� */
+const showTreeSkeleton = ref<boolean>(true);
+
+async function loadTree() {
+  showTreeSkeleton.value = true;
+  searchValue.value = '';
+  selectDeptId.value = [];
+
+  const ret = await getEquTypeTree();
+
+  deptTreeArray.value = ret;
+  showTreeSkeleton.value = false;
+}
+
+async function handleReload() {
+  await loadTree();
+  emit('reload');
+}
+
+onMounted(loadTree);
+</script>
+
+<template>
+  <div :class="$attrs.class">
+    <Skeleton
+      :loading="showTreeSkeleton"
+      :paragraph="{ rows: 8 }"
+      active
+      class="p-[8px]"
+    >
+      <div
+        class="bg-background flex h-full flex-col overflow-y-auto rounded-lg"
+      >
+        <!-- 鍥哄畾鍦ㄩ《閮� 蹇呴』鍔犱笂bg-background鑳屾櫙鑹� 鍚﹀垯浼氫骇鐢�'绌块��'鏁堟灉 -->
+        <div class="bg-background z-100 sticky left-0 top-0 p-[8px]">
+          <InputSearch
+            v-model:value="searchValue"
+            :placeholder="$t('pages.common.search')"
+            size="small"
+          >
+            <template #enterButton>
+              <a-button @click="handleReload">
+                <SyncOutlined class="text-primary" />
+              </a-button>
+            </template>
+          </InputSearch>
+        </div>
+        <div class="h-full overflow-x-hidden px-[8px]">
+          <Tree
+            v-bind="$attrs"
+            v-if="deptTreeArray.length > 0"
+            v-model:selected-keys="selectDeptId"
+            :class="$attrs.class"
+            :field-names="{ title: 'label', key: 'id' }"
+            :show-line="{ showLeafIcon: false }"
+            :tree-data="deptTreeArray"
+            :virtual="false"
+            default-expand-all
+            @select="$emit('select')"
+          >
+            <template #title="{ label }">
+              <span v-if="label.indexOf(searchValue) > -1">
+                {{ label.substring(0, label.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{
+                  label.substring(
+                    label.indexOf(searchValue) + searchValue.length,
+                  )
+                }}
+              </span>
+              <span v-else>{{ label }}</span>
+            </template>
+          </Tree>
+          <!-- 浠呮湰浜烘暟鎹潈闄� 鍙互鑰冭檻鐩存帴涓嶆樉绀� -->
+          <div v-else class="mt-5">
+            <Empty
+              :image="Empty.PRESENTED_IMAGE_SIMPLE"
+              description="鏃犺澶囩被鍨嬫暟鎹�"
+            />
+          </div>
+        </div>
+      </div>
+    </Skeleton>
+  </div>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fault-know/fault-know-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/fault-know/fault-know-drawer.vue
new file mode 100644
index 0000000..799fd77
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fault-know/fault-know-drawer.vue
@@ -0,0 +1,114 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { cloneDeep } from '@vben/utils';
+
+import { InputSearch } from 'ant-design-vue';
+
+import { useVbenForm } from '#/adapter/form';
+import { addFaultKnow, getFaultKnow, updateFaultKnow } from '#/api/eims/fault-know';
+import CodeInput from '#/views/eims/components/code-input.vue';
+import equModal from '#/views/eims/components/equ-modal.vue';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+
+    isUpdate.value = !!id;
+
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getFaultKnow(id);
+      await formApi.setValues(record);
+    }
+    drawerApi.drawerLoading(false);
+  }
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateFaultKnow(data) : addFaultKnow(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+
+// EQU modal
+const [EquModal, equModalApi] = useVbenModal({
+  connectedComponent: equModal,
+  draggable: true,
+  title: '閫夋嫨璁惧'
+});
+
+function handleEquModal() {
+  equModalApi.setData({});
+  equModalApi.open();
+}
+
+/**
+ * 鏇存柊閫夋嫨鐨勮澶�
+ * @param equ
+ */
+async function updateEqu(equ: any) {
+  await formApi.setValues({ 'equId': equ.equId, 'equName': equ.equName, 'equTypeId': equ.equTypeId });
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #faultCode="slotProps">
+        <CodeInput v-bind="slotProps" :disabled="isUpdate" prefix="GZZS" />
+      </template>
+      <template #equName="slotProps">
+        <InputSearch :enter-button="true" placeholder="璇烽�夋嫨璁惧" @search="handleEquModal" v-bind="slotProps" :disabled="isUpdate" />
+      </template>
+    </BasicForm>
+    <EquModal class="w-[1200px]" @update-equ="updateEqu" />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fault-know/index.vue b/eims-ui/apps/web-antd/src/views/eims/fault-know/index.vue
new file mode 100644
index 0000000..5d298b3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fault-know/index.vue
@@ -0,0 +1,194 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+import { delFaultKnow, faultKnowExport, listFaultKnow } from '#/api/eims/fault-know';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import EquTypeTree from './equ-type-tree.vue';
+import faultKnowDrawer from './fault-know-drawer.vue';
+
+// 宸﹁竟閮ㄩ棬鐢�
+const selectDeptId = ref<string[]>([]);
+
+defineExpose({
+  tableSelect
+});
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  handleReset: async () => {
+    selectDeptId.value = [];
+    // eslint-disable-next-line no-use-before-define
+    const { formApi, reload } = tableApi;
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    await reload(formValues);
+  },
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [['deployDate', ['params[beginTime]', 'params[endTime]'], ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']]]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectDeptId.value.length === 1 && selectDeptId.value[0] !== '0') {
+          formValues.equTypeId = selectDeptId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'equTypeId');
+        }
+        return await listFaultKnow({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'eims-fault-know-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+const [FaultKnowDrawer, faultKnowDrawerApi] = useVbenDrawer({
+  connectedComponent: faultKnowDrawer
+});
+
+function handleAdd() {
+  faultKnowDrawerApi.setData({});
+  faultKnowDrawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  faultKnowDrawerApi.setData({ id: record.id });
+  faultKnowDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delFaultKnow(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delFaultKnow(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(faultKnowExport, '鏁呴殰鐭ヨ瘑', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+
+// 閫変腑鏁版嵁
+function tableSelect() {
+  return tableApi.grid.getCheckboxRecords();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <EquTypeTree v-model:select-dept-id="selectDeptId" class="w-[260px]" @reload="() => tableApi.reload()" @select="() => tableApi.reload()" />
+      <BasicTable class="flex-1 overflow-hidden" table-title="璁惧鍒楄〃">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:faultKnow:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:faultKnow:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:faultKnow:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #equName="{ row }">
+          <Space>
+            <a-button type="link"> {{ row.equName }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:faultKnow:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:faultKnow:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <FaultKnowDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue
index e0f1e9e..a22f2f7 100644
--- a/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue
@@ -90,7 +90,7 @@
         <span>鍏佽瀵煎叆xlsx, xls鏂囦欢</span>
         <a-button
           type="link"
-          @click="commonDownloadExcel(downloadImportTemplate, '璁惧瀵煎叆妯℃澘')"
+          @click="commonDownloadExcel(downloadImportTemplate, '宸ュ叿瀵煎叆妯℃澘')"
         >
           <div class="flex items-center gap-[4px]">
             <ExcelIcon />
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue
index cdcde58..ef65b27 100644
--- a/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue
@@ -18,8 +18,8 @@
 import fixtureBorrowDrawer from '#/views/eims/fixture-borrow/fixture-borrow-drawer.vue';
 
 import { columns, querySchema } from './data';
-import fixtureDrawer from './fixture-drawer.vue';
 import fixtureBorrowListDrawer from './fixture-borrow-list-drawer.vue';
+import fixtureDrawer from './fixture-drawer.vue';
 import fixtureImportModal from './fixture-import-modal.vue';
 import FixtureTypeTree from './fixture-type-tree.vue';
 
@@ -108,7 +108,7 @@
     sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
     cellClick: (e: any) => {
       const { row } = e;
-      handleBorroeList(row)
+      handleBorroeList(row);
     }
   }
 });
@@ -300,9 +300,9 @@
             <a-button v-access:code="['eims:fixture:export']" @click="handleDownloadExcel">
               {{ $t('pages.common.export') }}
             </a-button>
-            <a-button v-access:code="['eims:fixture:import']" @click="handleImport">
+            <!-- <a-button v-access:code="['eims:fixture:import']" @click="handleImport">
               {{ $t('pages.common.import') }}
-            </a-button>
+            </a-button>-->
             <a-button
               :disabled="!vxeCheckboxChecked(tableApi)"
               danger
diff --git a/eims-ui/apps/web-antd/src/views/eims/insp-plan/data.tsx b/eims-ui/apps/web-antd/src/views/eims/insp-plan/data.tsx
index 1b14461..b07a476 100644
--- a/eims-ui/apps/web-antd/src/views/eims/insp-plan/data.tsx
+++ b/eims-ui/apps/web-antd/src/views/eims/insp-plan/data.tsx
@@ -258,7 +258,7 @@
       getPopupContainer
     },
     fieldName: 'inspFirstTime',
-    label: '棣栨淇濆吇鏃堕棿'
+    label: '棣栨鐐规鏃堕棿'
   },
   {
     component: 'DatePicker',
@@ -269,7 +269,7 @@
       getPopupContainer
     },
     fieldName: 'inspLastTime',
-    label: '涓婃淇濆吇鏃堕棿'
+    label: '涓婃鐐规鏃堕棿'
   },
   {
     component: 'DatePicker',
@@ -280,7 +280,7 @@
       getPopupContainer
     },
     fieldName: 'inspNextTime',
-    label: '涓嬫淇濆吇鏃堕棿',
+    label: '涓嬫鐐规鏃堕棿',
   },
   {
     component: 'Textarea',
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx
new file mode 100644
index 0000000..3d02eb4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx
@@ -0,0 +1,156 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'orderCode',
+    label: '鍏ュ簱鍗曞彿'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'chargeDept',
+    label: '缁忓姙閮ㄩ棬'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'chargeUser',
+    label: '缁忓姙浜�'
+  },
+  {
+    component: 'Input',
+    fieldName: 'partnerName',
+    label: '渚涘簲鍟�'
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'orderTime',
+    label: '宸ュ崟鏃堕棿'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '鍏ュ簱鍗曞彿',
+    field: 'orderCode',
+    minWidth: 100,
+    fixed: 'left',
+    slots: { default: 'orderCode' }
+  },
+  {
+    title: '鏃ユ湡',
+    field: 'orderTime',
+    minWidth: 120
+  },
+  {
+    title: '渚涘簲鍟�',
+    field: 'partnerName',
+    minWidth: 100
+  },
+  {
+    title: '缁忓姙浜�',
+    field: 'chargeUserName',
+    minWidth: 100
+  },
+  {
+    title: '鍏宠仈鍗曞彿',
+    field: 'associatedOrder',
+    minWidth: 120
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+    minWidth: 140
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'id'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SPARE_INOUT_TYPE)
+    },
+    dependencies: {
+      show: () => true,
+      triggerFields: ['']
+    },
+    fieldName: 'type',
+    defaultValue: '1',
+    label: '绫诲瀷'
+  },
+  {
+    component: 'Input',
+    fieldName: 'orderCode',
+    label: '鍏ュ簱鍗曞彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'partnerName',
+    label: '渚涘簲鍟�'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'chargeDept',
+    label: '缁忓姙閮ㄩ棬',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'chargeUser',
+    label: '缁忓姙浜�',
+    rules: 'required'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD HH:mm:ss',
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      getPopupContainer
+    },
+    fieldName: 'orderTime',
+    label: '鍏ュ簱鏃堕棿'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'remark',
+    label: '澶囨敞'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue
new file mode 100644
index 0000000..7a054c4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue
@@ -0,0 +1,237 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, getPopupContainer, getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+import { delSpareInout, listSpareInout, spareInoutExport } from '#/api/eims/spare-inout';
+import { getDeptTree, userList } from '#/api/system/user';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import drawer from './spare-in-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  collapsed: true,
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [['orderTime', ['params[beginOrderTime]', 'params[endOrderTime]'], ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']]]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 1-鍏ュ簱鍗� 2-鍑哄簱鍗�
+        formValues.type = '1';
+        return await listSpareInout({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'spre-inout-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  connectedComponent: drawer
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.id });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delSpareInout(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delSpareInout(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(spareInoutExport, '澶囦欢鍏ュ簱鍗曡褰�', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'chargeUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.chargeUser = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'chargeDept'
+    }
+  ]);
+}
+
+onMounted(async () => {
+  await setupDeptSelect();
+});
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍏ュ簱鍗曞垪琛�">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:spareInout:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:spareInout:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:spareInout:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #orderCode="{ row }">
+          <Space>
+            <a-button type="link"> {{ row.orderCode }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:spareInout:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:spareInout:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <Drawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue
new file mode 100644
index 0000000..263c7ac
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue
@@ -0,0 +1,155 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addSpareInout, getSpareInout, updateSpareInout } from '#/api/eims/spare-inout';
+import { getDeptTree, userList } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+import CodeInput from '#/views/eims/components/code-input.vue';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getSpareInout(id);
+      await formApi.setValues(record);
+    }
+
+    drawerApi.drawerLoading(false);
+  }
+});
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'chargeUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.operatorId = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'chargeDept'
+    }
+  ]);
+}
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateSpareInout(data) : addSpareInout(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #orderCode="slotProps">
+        <CodeInput v-bind="slotProps" :disabled="isUpdate" prefix="RK" />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx
new file mode 100644
index 0000000..dd1dbc0
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx
@@ -0,0 +1,156 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'orderCode',
+    label: '鍑哄簱鍗曞彿'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'chargeDept',
+    label: '缁忓姙閮ㄩ棬'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'chargeUser',
+    label: '缁忓姙浜�'
+  },
+  {
+    component: 'Input',
+    fieldName: 'partnerName',
+    label: '瀹㈡埛'
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'orderTime',
+    label: '宸ュ崟鏃堕棿'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '鍑哄簱鍗曞彿',
+    field: 'orderCode',
+    minWidth: 100,
+    fixed: 'left',
+    slots: { default: 'orderCode' }
+  },
+  {
+    title: '鏃ユ湡',
+    field: 'orderTime',
+    minWidth: 120
+  },
+  {
+    title: '瀹㈡埛',
+    field: 'partnerName',
+    minWidth: 100
+  },
+  {
+    title: '缁忓姙浜�',
+    field: 'chargeUserName',
+    minWidth: 100
+  },
+  {
+    title: '鍏宠仈鍗曞彿',
+    field: 'associatedOrder',
+    minWidth: 120
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+    minWidth: 140
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'id'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SPARE_INOUT_TYPE)
+    },
+    dependencies: {
+      show: () => true,
+      triggerFields: ['']
+    },
+    fieldName: 'type',
+    defaultValue: '2',
+    label: '绫诲瀷'
+  },
+  {
+    component: 'Input',
+    fieldName: 'orderCode',
+    label: '鍑哄簱鍗曞彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'partnerName',
+    label: '瀹㈡埛'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'chargeDept',
+    label: '缁忓姙閮ㄩ棬',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'chargeUser',
+    label: '缁忓姙浜�',
+    rules: 'required'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD HH:mm:ss',
+      showTime: true,
+      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      getPopupContainer
+    },
+    fieldName: 'orderTime',
+    label: '鍑哄簱鏃堕棿'
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'remark',
+    label: '澶囨敞'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue
new file mode 100644
index 0000000..764ec4a
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue
@@ -0,0 +1,237 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, getPopupContainer, getVxePopupContainer } from '@vben/utils';
+
+import { Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+import { delSpareInout, listSpareInout, spareInoutExport } from '#/api/eims/spare-inout';
+import { getDeptTree, userList } from '#/api/system/user';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import drawer from './spare-out-drawer.vue';
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  collapsed: true,
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [['orderTime', ['params[beginOrderTime]', 'params[endOrderTime]'], ['YYYY-MM-DD 00:00:00', 'YYYY-MM-DD 23:59:59']]]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 1-鍏ュ簱鍗� 2-鍑哄簱鍗�
+        formValues.type = '2';
+        return await listSpareInout({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'spre-inout-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+const [Drawer, drawerApi] = useVbenDrawer({
+  connectedComponent: drawer
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.id });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delSpareInout(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delSpareInout(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(spareInoutExport, '澶囦欢鍑哄簱鍗曡褰�', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'chargeUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  tableApi.formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.chargeUser = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'chargeDept'
+    }
+  ]);
+}
+
+onMounted(async () => {
+  await setupDeptSelect();
+});
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍑哄簱鍗曞垪琛�">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:spareInout:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:spareInout:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:spareInout:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #orderCode="{ row }">
+          <Space>
+            <a-button type="link"> {{ row.orderCode }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:spareInout:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:spareInout:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <Drawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue
new file mode 100644
index 0000000..ebd82a4
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue
@@ -0,0 +1,155 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addSpareInout, getSpareInout, updateSpareInout } from '#/api/eims/spare-inout';
+import { getDeptTree, userList } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+import CodeInput from '#/views/eims/components/code-input.vue';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getSpareInout(id);
+      await formApi.setValues(record);
+    }
+
+    drawerApi.drawerLoading(false);
+  }
+});
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+async function setupUserOptions(deptId: any) {
+  const params = { deptId };
+  const userPageResult = await userList({
+    pageNum: 1,
+    pageSize: 500,
+    ...params
+  });
+  const options = userPageResult.rows.map((item) => ({
+    label: item.nickName || item.userName,
+    value: item.userId
+  }));
+  // 绛涢��
+  const filterOption = (input: string, option: any) => {
+    return option.label.toLowerCase().includes(input.toLowerCase());
+  };
+
+  const placeholder = options.length > 0 ? '璇烽�夋嫨' : '璇ラ儴闂ㄤ笅鏆傛棤鐢ㄦ埛';
+  formApi.updateSchema([
+    {
+      componentProps: { options, placeholder, filterOption },
+      fieldName: 'chargeUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+async function setupDeptSelect() {
+  // updateSchema
+  const deptTree = await getDeptTree();
+  // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊� 鍗崇埗鑺傜偣 / 瀛愯妭鐐�
+  addFullName(deptTree, 'label', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: (formModel) => ({
+        class: 'w-full',
+        fieldNames: {
+          key: 'id',
+          value: 'id',
+          children: 'children'
+        },
+        getPopupContainer,
+        async onSelect(deptId: number | string) {
+          /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
+          await setupUserOptions(deptId);
+          /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
+          formModel.operatorId = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'chargeDept'
+    }
+  ]);
+}
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateSpareInout(data) : addSpareInout(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #orderCode="slotProps">
+        <CodeInput v-bind="slotProps" :disabled="isUpdate" prefix="CK" />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-type/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-type/data.tsx
new file mode 100644
index 0000000..838ba58
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-type/data.tsx
@@ -0,0 +1,196 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { h } from 'vue';
+
+import { DictEnum } from '@vben/constants';
+import { FolderIcon, MenuIcon, VbenIcon } from '@vben/icons';
+import { getPopupContainer } from '@vben/utils';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'typeName',
+    label: '绫诲瀷鍚嶇О '
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE)
+    },
+    fieldName: 'status',
+    label: '绫诲瀷鐘舵�� '
+  }
+];
+
+// 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+export const spareTypeOptions = [
+  { label: '澶囦欢鐩綍', value: 'M' },
+  { label: '澶囦欢绫诲瀷', value: 'C' }
+];
+
+export const yesNoOptions = [
+  { label: '鏄�', value: '0' },
+  { label: '鍚�', value: '1' }
+];
+
+// 锛圡鐩綍 C鑿滃崟锛�
+const menuTypes = {
+  M: { icon: FolderIcon, value: '澶囦欢鐩綍' },
+  C: { icon: MenuIcon, value: '澶囦欢绫诲瀷' }
+};
+export const columns: VxeGridProps['columns'] = [
+  {
+    title: '绫诲瀷鍚嶇О',
+    field: 'typeName',
+    treeNode: true,
+    width: 200
+  },
+  {
+    title: '绫诲瀷缂栫爜',
+    field: 'typeCode',
+    width: 200
+  },
+  {
+    title: '鍥炬爣',
+    field: 'icon',
+    width: 80,
+    slots: {
+      default: ({ row }) => {
+        if (row?.icon === '#') {
+          return '';
+        }
+        return (
+          <span class={'flex justify-center'}>
+            <VbenIcon icon={row.icon} />
+          </span>
+        );
+      }
+    }
+  },
+  {
+    title: '鎺掑簭',
+    field: 'orderNum',
+    width: 120
+  },
+  {
+    title: '鑺傜偣绫诲瀷',
+    field: 'menuType',
+    width: 150,
+    slots: {
+      default: ({ row }) => {
+        const current = menuTypes[row.menuType as 'C' | 'M'];
+        if (!current) {
+          return '鏈煡';
+        }
+        return (
+          <span class="flex items-center justify-center gap-1">
+            {h(current.icon, { class: 'size-[18px]' })}
+            <span>{current.value}</span>
+          </span>
+        );
+      }
+    }
+  },
+  {
+    title: '鐘舵��',
+    field: 'status',
+    width: 100,
+    slots: {
+      default: ({ row }) => {
+        return renderDict(row.status, DictEnum.SYS_NORMAL_DISABLE);
+      }
+    }
+  },
+  {
+    title: '鍒涘缓鏃堕棿',
+    field: 'createTime'
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 200
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'id'
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: 0,
+    fieldName: 'parentId',
+    label: '涓婄骇鑿滃崟',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: spareTypeOptions,
+      optionType: 'button'
+    },
+    defaultValue: 'M',
+    dependencies: {
+      componentProps: (_, api) => {
+        // 鍒囨崲鏃舵竻绌烘牎楠�
+        // 鐩存帴鎶勭殑婧愮爜 娌℃湁娓呯┖鏍¢獙鐨勬柟娉�
+        Object.keys(api.errors.value).forEach((key) => {
+          api.setFieldError(key, undefined);
+        });
+        return {};
+      },
+      triggerFields: ['menuType']
+    },
+    fieldName: 'menuType',
+    label: '鑺傜偣绫诲瀷'
+  },
+  {
+    component: 'Input',
+    fieldName: 'typeName',
+    label: '绫诲瀷鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'typeCode',
+    label: '绫诲瀷缂栫爜',
+    rules: 'required'
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'orderNum',
+    help: '鎺掑簭, 鏁板瓧瓒婂皬瓒婇潬鍓�',
+    label: '鏄剧ず鎺掑簭',
+    rules: 'required'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.SYS_NORMAL_DISABLE),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    dependencies: {
+      // 绫诲瀷涓嶄负鎸夐挳鏃舵樉绀�
+      show: (values) => values.menuType !== 'F',
+      triggerFields: ['menuType']
+    },
+    fieldName: 'status',
+    help: '鍋滅敤鍚庝笉浼氬嚭鐜板湪鍒楄〃',
+    label: '绫诲瀷鐘舵��'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-type/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare-type/index.vue
new file mode 100644
index 0000000..934c166
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-type/index.vue
@@ -0,0 +1,170 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { eachTree, getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { delSpareType, spareTypeExport, listSpareType } from '#/api/eims/spare-type';
+import { $t } from '@vben/locales';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import spareTypeDrawer from './spare-type-drawer.vue';
+
+/**
+ * 涓嶈闂负浠�涔堟湁涓や釜鏍硅妭鐐� v-if浼氭帶鍒跺彧浼氭覆鏌撲竴涓�
+ */
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4'
+};
+
+const gridOptions: VxeGridProps = {
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false
+  },
+  proxyConfig: {
+    ajax: {
+      query: async (_, formValues = {}) => {
+        const resp = await listSpareType({
+          ...formValues
+        });
+        return { rows: resp };
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  /**
+   * 寮�鍚櫄鎷熸粴鍔�
+   * 鏁版嵁閲忓皬鍙互閫夋嫨鍏抽棴
+   * 濡傛灉閬囧埌鏍峰紡闂(绌虹櫧銆侀敊浣� 婊氬姩绛�)鍙互閫夋嫨鍏抽棴铏氭嫙婊氬姩
+   */
+  scrollY: {
+    enabled: true,
+    gt: 0
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    // 鑷姩杞崲涓簍ree 鐢眝xe澶勭悊 鏃犻渶鎵嬪姩杞崲
+    transform: true
+  },
+  id: 'spare-type-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    cellDblclick: (e: any) => {
+      const { row = {} } = e;
+      if (!row?.children) {
+        return;
+      }
+      const isExpanded = row?.expand;
+      tableApi.grid.setTreeExpand(row, !isExpanded);
+      row.expand = !isExpanded;
+    },
+    // 闇�瑕佺洃鍚娇鐢ㄧ澶村睍寮�鐨勬儏鍐� 鍚﹀垯灞曞紑/鎶樺彔鐨勬暟鎹笉涓�鑷�
+    toggleTreeExpand: (e: any) => {
+      const { row = {}, expanded } = e;
+      row.expand = expanded;
+    }
+  }
+});
+const [SpareTypeDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: spareTypeDrawer
+});
+
+function handleAdd() {
+  drawerApi.setData({});
+  drawerApi.open();
+}
+
+function handleSubAdd(row: Recordable<any>) {
+  const { id } = row;
+  drawerApi.setData({ id, update: false });
+  drawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  drawerApi.setData({ id: record.id, update: true });
+  drawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delSpareType(row.id);
+  await tableApi.query();
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(spareTypeExport, '澶囦欢绫诲瀷', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+/**
+ * 鍏ㄩ儴灞曞紑/鎶樺彔
+ * @param expand 鏄惁灞曞紑
+ */
+function setExpandOrCollapse(expand: boolean) {
+  eachTree(tableApi.grid.getData(), (item) => (item.expand = expand));
+  tableApi.grid?.setAllTreeExpand(expand);
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <BasicTable table-title="澶囦欢绫诲瀷鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
+      <template #toolbar-tools>
+        <Space>
+          <a-button @click="setExpandOrCollapse(false)">
+            {{ $t('pages.common.collapse') }}
+          </a-button>
+          <a-button @click="setExpandOrCollapse(true)">
+            {{ $t('pages.common.expand') }}
+          </a-button>
+          <a-button v-access:code="['eims:spareType:export']" @click="handleDownloadExcel">
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button type="primary" v-access:code="['eims:spareType:add']" @click="handleAdd">
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button v-access:code="['eims:spareType:edit']" @click="handleEdit(row)">
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <!-- '鎸夐挳绫诲瀷'鏃犳硶鍐嶆坊鍔犲瓙鑿滃崟 -->
+          <ghost-button v-if="row.menuType !== 'F'" class="btn-success" v-access:code="['eims:spareType:add']" @click="handleSubAdd(row)">
+            {{ $t('pages.common.add') }}
+          </ghost-button>
+          <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+            <ghost-button danger v-access:code="['eims:spareType:remove']" @click.stop="">
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <SpareTypeDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-type/spare-type-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare-type/spare-type-drawer.vue
new file mode 100644
index 0000000..510a19f
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-type/spare-type-drawer.vue
@@ -0,0 +1,132 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addSpareType, getSpareType, listSpareType, updateSpareType } from '#/api/eims/spare-type';
+
+import { drawerSchema } from './data';
+
+interface ModalProps {
+  id?: number | string;
+  update: boolean;
+}
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    componentProps: {
+      class: 'w-full'
+    },
+    formItemClass: 'col-span-2',
+    labelWidth: 90
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+async function setupSpareTypeSelect() {
+  // menu
+  const menuArray = await listSpareType({ status: '0' });
+  // support i18n
+  menuArray.forEach((item) => {
+    item.typeName = $t(item.typeName);
+  });
+  // const folderArray = menuArray.filter((item) => item.menuType === 'M');
+  const menuTree = listToTree(menuArray, { id: 'id', pid: 'parentId' });
+  const fullMenuTree = [
+    {
+      id: 0,
+      typeName: $t('menu.root'),
+      children: menuTree
+    }
+  ];
+  addFullName(fullMenuTree, 'typeName', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'typeName',
+          value: 'id'
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullMenuTree,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'typeName',
+        treeNodeLabelProp: 'fullName'
+      },
+      fieldName: 'parentId'
+    }
+  ]);
+}
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id, update } = drawerApi.getData() as ModalProps;
+    isUpdate.value = update;
+
+    // 鍔犺浇璁惧绫诲瀷鏍戦�夋嫨
+    await setupSpareTypeSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (update) {
+        const record = await getSpareType(id);
+        await formApi.setValues(record);
+      }
+    }
+    drawerApi.drawerLoading(false);
+  }
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateSpareType(data) : addSpareType(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm />
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx
new file mode 100644
index 0000000..8228ae6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx
@@ -0,0 +1,282 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { DictEnum } from '@vben/constants';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { getDictOptions } from '#/utils/dict';
+import { renderDict } from '#/utils/render';
+import { getPopupContainer } from '@vben/utils';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'name',
+    label: '澶囦欢鍚嶇О'
+  },
+  {
+    component: 'Input',
+    fieldName: 'code',
+    label: '澶囦欢缂栫爜'
+  },
+  {
+    component: 'Input',
+    fieldName: 'modelNo',
+    label: '澶囦欢鍨嬪彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'madeIn',
+    label: '鐢熶骇浜у晢'
+  },
+  {
+    component: 'Input',
+    fieldName: 'supplier',
+    label: '渚涘簲鍟�'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '澶囦欢棰勮',
+    field: 'imgUrl',
+    showOverflow: true,
+    width: 100,
+    fixed: 'left',
+    align: 'center',
+    slots: { default: 'imgUrl' }
+  },
+  {
+    title: '澶囦欢鍚嶇О',
+    field: 'name',
+    fixed: 'left',
+    align: 'center',
+    width: 200
+  },
+  {
+    title: '澶囦欢缂栫爜',
+    field: 'code',
+    width: 140
+  },
+  {
+    title: '澶囦欢鍨嬪彿',
+    field: 'modelNo',
+    width: 100
+  },
+  {
+    title: '澶囦欢绫诲瀷',
+    field: 'typeName',
+    width: 100
+  },
+  {
+    title: '鐢熶骇浜у晢',
+    field: 'madeIn',
+    width: 140
+  },
+  {
+    title: '渚涘簲鍟�',
+    field: 'supplier',
+    width: 140
+  },
+  {
+    title: '璁¢噺鍗曚綅',
+    field: 'unit',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (row.unit === null || row.unit === '') {
+          return '';
+        }
+        return renderDict(row.unit, DictEnum.EIMS_SPARE_UNIT);
+      }
+    },
+    width: 100
+  },
+  {
+    title: '鍙傝�冧环',
+    field: 'referPrice',
+    sortable: true,
+    width: 120
+  },
+  {
+    title: '搴撳瓨涓婇檺',
+    field: 'upperStock',
+    sortable: true,
+    width: 120
+  },
+  {
+    title: '搴撳瓨涓嬮檺',
+    field: 'lowerStock',
+    width: 120
+  },
+  {
+    title: '瀹為檯搴撳瓨',
+    field: 'actualStock',
+    width: 120
+  },
+  {
+    title: '搴撳瓨閲戦',
+    field: 'stockAmount',
+    width: 120
+  },
+  {
+    title: '鏇存崲鍛ㄦ湡',
+    field: 'replaceCycle',
+    width: 120
+  },
+  {
+    title: '澶囨敞',
+    field: 'remark',
+    width: 120
+  },
+  {
+    field: 'action',
+    fixed: 'right',
+    slots: { default: 'action' },
+    title: '鎿嶄綔',
+    width: 180
+  }
+];
+
+export const drawerSchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['']
+    },
+    fieldName: 'id'
+  },
+  {
+    component: 'TreeSelect',
+    defaultValue: 0,
+    fieldName: 'type',
+    label: '澶囦欢绫诲瀷',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Input',
+    fieldName: 'name',
+    label: '澶囦欢鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'code',
+    label: '澶囦欢缂栫爜',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'img',
+    dependencies: {
+      show: () => false,
+      triggerFields: ['imgUrl']
+    },
+    label: '澶囦欢棰勮',
+  },
+  {
+    component: 'Input',
+    fieldName: 'imgUrl',
+    label: '澶囦欢棰勮'
+  },
+  {
+    component: 'Input',
+    fieldName: 'modelNo',
+    label: '鍨嬪彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'madeIn',
+    label: '鐢熶骇浜у晢'
+  },
+  {
+    component: 'Input',
+    fieldName: 'supplier',
+    label: '渚涘簲鍟�'
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'referPrice',
+    label: '鍙傝�冧环鏍�',
+    componentProps: {
+      min: 0,
+      precision: 2,
+      addonAfter: '锟�',
+      placeholder: '璇疯緭鍏�'
+    }
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'upperStock',
+    label: '搴撳瓨涓婇檺',
+    componentProps: {
+      min: 0
+    }
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'lowerStock',
+    label: '搴撳瓨涓嬮檺',
+    componentProps: {
+      min: 0
+    }
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'actualStock',
+    formItemClass: 'col-span-1',
+    label: '瀹為檯搴撳瓨',
+    componentProps: {
+      min: 0
+    }
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.EIMS_SPARE_UNIT)
+    },
+    fieldName: 'unit',
+    formItemClass: 'col-span-1 w-[80px]',
+    labelWidth: 0,
+    label: ''
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'stockAmount',
+    label: '搴撳瓨閲戦',
+    componentProps: {
+      min: 0,
+      precision: 2,
+      addonAfter: '锟�',
+      placeholder: '璇疯緭鍏�'
+    }
+  },
+  {
+    component: 'InputNumber',
+    fieldName: 'replaceCycle',
+    formItemClass: 'col-span-1',
+    label: '鏇存崲鍛ㄦ湡',
+    componentProps: {
+      min: 0
+    }
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      getPopupContainer,
+      options: getDictOptions(DictEnum.MAINT_CYCLE_UNIT)
+    },
+    fieldName: 'cycleUnit',
+    formItemClass: 'col-span-1 w-[80px]',
+    labelWidth: 0,
+    label: ''
+  },
+  {
+    component: 'Textarea',
+    formItemClass: 'items-baseline',
+    fieldName: 'remark',
+    label: '澶囨敞'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare/index.vue
new file mode 100644
index 0000000..1682ab2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/index.vue
@@ -0,0 +1,217 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted, ref } from 'vue';
+
+import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Image, Modal, Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+import { delSpare, listSpare, spareExport } from '#/api/eims/spare';
+import { configInfoByKey } from '#/api/system/config';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import spareDrawer from './spare-drawer.vue';
+import SpareTypeTree from './spare-type-tree.vue';
+
+// 宸﹁竟閮ㄩ棬鐢�
+const selectTypeId = ref<any[]>([]);
+
+defineExpose({
+  tableSelect
+});
+
+const formOptions: VbenFormProps = {
+  commonConfig: {
+    labelWidth: 80,
+    componentProps: {
+      allowClear: true
+    }
+  },
+  collapsed: true,
+  schema: querySchema(),
+  wrapperClass: 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4',
+  handleReset: async () => {
+    selectTypeId.value = [];
+    // eslint-disable-next-line no-use-before-define
+    const { formApi, reload } = tableApi;
+    await formApi.resetForm();
+    const formValues = formApi.form.values;
+    formApi.setLatestSubmissionValues(formValues);
+    await reload(formValues);
+  }
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {
+    enabled: false,
+  },
+  proxyConfig: {
+    enabled: true,
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectTypeId.value.length === 1 && selectTypeId.value[0] !== 0) {
+          formValues.type = selectTypeId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'type');
+        }
+        return await listSpare({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  columnConfig: {
+    resizable: true,
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'eims-spare-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+const [SpareDrawer, spareDrawerApi] = useVbenDrawer({
+  connectedComponent: spareDrawer
+});
+
+function handleAdd() {
+  spareDrawerApi.setData({});
+  spareDrawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  spareDrawerApi.setData({ id: record.id });
+  spareDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delSpare(row.id);
+  await tableApi.query();
+}
+
+function handleMultiDelete() {
+  const rows = tableApi.grid.getCheckboxRecords();
+  const ids = rows.map((row: any) => row.id);
+  Modal.confirm({
+    title: '鎻愮ず',
+    okType: 'danger',
+    content: `纭鍒犻櫎閫変腑鐨�${ids.length}鏉¤褰曞悧锛焋,
+    onOk: async () => {
+      await delSpare(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(spareExport, '澶囦欢鍙拌处', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+const preview = ref(false);
+onMounted(async () => {
+  const resp = await configInfoByKey('sys.oss.previewListResource');
+  preview.value = Boolean(resp);
+});
+
+function isImageFile(ext: string) {
+  const supportList = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
+  return supportList.some((item) => ext.toLocaleLowerCase().includes(item));
+}
+
+// 閫変腑鏁版嵁
+function tableSelect() {
+  return tableApi.grid.getCheckboxRecords();
+}
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <SpareTypeTree v-model:select-type-id="selectTypeId" class="w-[260px]" @reload="() => tableApi.reload()" @select="() => tableApi.reload()" />
+      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍙拌处">
+        <template #toolbar-tools>
+          <Space>
+            <a-button v-access:code="['eims:spare:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:spare:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:spare:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #imgUrl="{ row }">
+          <Image v-if="preview && isImageFile(row.imgUrl)" :src="row.imgUrl" height="38px" />
+          <span v-else>{{ row.imgUrl }}</span>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:spare:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:spare:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <SpareDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
+
+<style>
+/* 缁熶竴鎵�鏈夊垪鐨勮竟妗嗗拰琛岄珮 */
+.vxe-table--body .vxe-body--row .vxe-body--column {
+  height: 56px !important;
+  box-sizing: border-box !important;
+  padding-top: 1px !important; /* 淇濇寔鍜屾櫘閫氬垪涓�鑷寸殑padding */
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/spare-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare/spare-drawer.vue
new file mode 100644
index 0000000..3ddb4f6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/spare-drawer.vue
@@ -0,0 +1,149 @@
+<script setup lang="ts">
+import { computed, ref } from 'vue';
+
+import { useVbenDrawer } from '@vben/common-ui';
+import { $t } from '@vben/locales';
+import { addFullName, cloneDeep, getPopupContainer, listToTree } from '@vben/utils';
+
+import { useVbenForm } from '#/adapter/form';
+import { addSpare, getSpare, updateSpare } from '#/api/eims/spare';
+import { listSpareType } from '#/api/eims/spare-type';
+import { ImageUpload } from '#/components/upload';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const isUpdate = ref(false);
+const title = computed(() => {
+  return isUpdate.value ? $t('pages.common.edit') : $t('pages.common.add');
+});
+
+
+const [BasicForm, formApi] = useVbenForm({
+  commonConfig: {
+    formItemClass: 'col-span-2',
+    componentProps: {
+      class: 'w-full'
+    },
+    labelWidth: 120
+  },
+  schema: drawerSchema(),
+  showDefaultActions: false,
+  wrapperClass: 'grid-cols-2'
+});
+
+const [BasicDrawer, drawerApi] = useVbenDrawer({
+  onCancel: handleCancel,
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    await setupSpareTypeSelect();
+    onImageChange();
+    isUpdate.value = !!id;
+
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getSpare(id);
+      await formApi.setValues(record);
+    }
+    drawerApi.drawerLoading(false);
+  }
+});
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateSpare(data) : addSpare(data));
+    emit('reload');
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    drawerApi.drawerLoading(false);
+  }
+}
+
+async function handleCancel() {
+  drawerApi.close();
+  await formApi.resetForm();
+}
+
+async function setupSpareTypeSelect() {
+  // status-0 鍙煡璇㈡湭鍋滅敤
+  const equArray = await listSpareType({ status: 0 });
+  // support i18n
+  equArray.forEach((item) => {
+    item.typeName = $t(item.typeName);
+  });
+  const equTree = listToTree(equArray, { id: 'id', pid: 'parentId' });
+  const fullEquTree = [
+    {
+      id: 0,
+      typeName: $t('menu.root'),
+      children: equTree
+    }
+  ];
+  addFullName(fullEquTree, 'typeName', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'typeName',
+          value: 'id'
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullEquTree,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'typeName',
+        treeNodeLabelProp: 'fullName'
+      },
+      fieldName: 'type'
+    }
+  ]);
+}
+
+const accept = ref(['jpg', 'jpeg', 'png', 'gif', 'webp']);
+const maxNumber = ref(1);
+
+function onImageChange() {
+  formApi.updateSchema([
+    {
+      componentProps: () => ({
+        async onChange(value: any) {
+          await formApi.setValues({ 'img': value });
+        }
+      }),
+      fieldName: 'imgUrl'
+    }
+  ]);
+}
+</script>
+
+<template>
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+    <BasicForm>
+      <template #imgUrl="slotProps">
+        <!--娉ㄦ剰锛氫笂浼犳垚鍔熷悗杩斿洖ossid-->
+        <ImageUpload v-bind="slotProps" :accept="accept" :max-number="maxNumber"
+                     result-field="ossId" />
+      </template>
+    </BasicForm>
+  </BasicDrawer>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/spare-type-tree.vue b/eims-ui/apps/web-antd/src/views/eims/spare/spare-type-tree.vue
new file mode 100644
index 0000000..0ea4fa3
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/spare-type-tree.vue
@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import type { SpareTypeTree } from '#/api/eims/spare-type/model.d.ts';
+
+import { onMounted, type PropType, ref } from 'vue';
+
+import { SyncOutlined } from '@ant-design/icons-vue';
+import { Empty, InputSearch, Skeleton, Tree } from 'ant-design-vue';
+
+import { getSpareTypeTree } from '#/api/eims/spare-type';
+
+defineOptions({ inheritAttrs: false });
+
+const emit = defineEmits<{
+  /**
+   * 鐐瑰嚮鍒锋柊鎸夐挳鐨勪簨浠�
+   */
+  reload: [];
+  /**
+   * 鐐瑰嚮鑺傜偣鐨勪簨浠�
+   */
+  select: [];
+}>();
+
+const selectTypeId = defineModel('selectTypeId', {
+  required: true,
+  type: Array as PropType<string[]>,
+});
+
+const searchValue = defineModel('searchValue', {
+  type: String,
+  default: '',
+});
+
+/** 閮ㄩ棬鏁版嵁婧� */
+type TypeTreeArray = SpareTypeTree[];
+const spareTypeTreeArray = ref<TypeTreeArray>([]);
+/** 楠ㄦ灦灞忓姞杞� */
+const showTreeSkeleton = ref<boolean>(true);
+
+async function loadTree() {
+  showTreeSkeleton.value = true;
+  searchValue.value = '';
+  selectTypeId.value = [];
+
+  const ret = await getSpareTypeTree();
+
+  spareTypeTreeArray.value = ret;
+  showTreeSkeleton.value = false;
+}
+
+async function handleReload() {
+  await loadTree();
+  emit('reload');
+}
+
+onMounted(loadTree);
+</script>
+
+<template>
+  <div :class="$attrs.class">
+    <Skeleton
+      :loading="showTreeSkeleton"
+      :paragraph="{ rows: 8 }"
+      active
+      class="p-[8px]"
+    >
+      <div
+        class="bg-background flex h-full flex-col overflow-y-auto rounded-lg"
+      >
+        <!-- 鍥哄畾鍦ㄩ《閮� 蹇呴』鍔犱笂bg-background鑳屾櫙鑹� 鍚﹀垯浼氫骇鐢�'绌块��'鏁堟灉 -->
+        <div class="bg-background z-100 sticky left-0 top-0 p-[8px]">
+          <InputSearch
+            v-model:value="searchValue"
+            :placeholder="$t('pages.common.search')"
+            size="small"
+          >
+            <template #enterButton>
+              <a-button @click="handleReload">
+                <SyncOutlined class="text-primary" />
+              </a-button>
+            </template>
+          </InputSearch>
+        </div>
+        <div class="h-full overflow-x-hidden px-[8px]">
+          <Tree
+            v-bind="$attrs"
+            v-if="spareTypeTreeArray.length > 0"
+            v-model:selected-keys="selectTypeId"
+            :class="$attrs.class"
+            :field-names="{ title: 'label', key: 'id' }"
+            :show-line="{ showLeafIcon: false }"
+            :tree-data="spareTypeTreeArray"
+            :virtual="false"
+            default-expand-all
+            @select="$emit('select')"
+          >
+            <template #title="{ label }">
+              <span v-if="label.indexOf(searchValue) > -1">
+                {{ label.substring(0, label.indexOf(searchValue)) }}
+                <span style="color: #f50">{{ searchValue }}</span>
+                {{
+                  label.substring(
+                    label.indexOf(searchValue) + searchValue.length,
+                  )
+                }}
+              </span>
+              <span v-else>{{ label }}</span>
+            </template>
+          </Tree>
+          <!-- 浠呮湰浜烘暟鎹潈闄� 鍙互鑰冭檻鐩存帴涓嶆樉绀� -->
+          <div v-else class="mt-5">
+            <Empty
+              :image="Empty.PRESENTED_IMAGE_SIMPLE"
+              description="鏃犺澶囩被鍨嬫暟鎹�"
+            />
+          </div>
+        </div>
+      </div>
+    </Skeleton>
+  </div>
+</template>
diff --git a/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts b/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts
index 3052f3d..60fdb65 100644
--- a/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts
+++ b/eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts
@@ -1,11 +1,15 @@
 export enum DictEnum {
+  EIMS_EQU_PART = 'eims_equ_part', // 璁惧閮ㄤ綅
+  EIMS_SPARE_UNIT = 'eims_spare_unit', // 澶囦欢璁¢噺鍗曚綅
   EIMS_EQU_UNIT = 'eims_equ_unit', // 璁惧鐩樼偣鐘舵��
+  EIMS_FAULT_REASON = 'eims_fault_reason', // 鏁呴殰鍘熷洜
   EIMS_FIXTURE_STATUS = 'eims_fixture_status', // 宸ュ叿锛堟不鍏凤級鐘舵��
+  EIMS_INSPECT_RESULT = 'eims_inspect_result', // 鐐规缁撴灉
+  EIMS_INSPECT_STATUS = 'eims_inspect_status', // 鐐规鐘舵��
   EIMS_INSPECT_TYPE = 'eims_inspect_type', // 鐐规绫诲瀷
   EIMS_INVENTORY_DETAIL_STATU = 'inventory_detail_statu', // 璁惧鐩樼偣鐘舵��
   EIMS_INVENTORY_STATU = 'inventory_statu', // 璁惧鐩樼偣鐘舵��
   EIMS_MAINT_TYPE = 'eims_maint_type', // 淇濆吇绫诲瀷
-  EIMS_INSPECT_RESULT = 'eims_inspect_result', // 鐐规缁撴灉
   EIMS_ORDITM_STATUS = 'eims_orditm_status', // 淇濆吇宸ュ崟鏄庣粏瀹屾垚鐘舵��
   EQU_IMPORT_STATU = 'equ_import_status', // 璁惧瀵煎叆鐘舵��
   FIXTURE_BORROW_RECORD_STATUS = 'fixture_borrow_record_status', // 宸ュ叿锛堟不鍏凤級鍊熺敤璁板綍鐘舵��
@@ -13,11 +17,11 @@
   MAINT_CYCLE_UNIT = 'maint_cycle_unit', // 淇濆吇鍛ㄦ湡鍗曚綅
   MAINT_ORDER_ST_STATUS = 'maint_order_st_status', // 淇濆吇宸ュ崟姹囨�荤ń鏌ョ姸鎬�
   MAINT_ORDER_STATUS = 'maint_order_status', // 淇濆吇宸ュ崟鐘舵��
-  EIMS_INSPECT_STATUS = 'eims_inspect_status', // 鐐规鐘舵��
   MAINT_TIME_RULE = 'maint_time_rule', // 淇濆吇瑙勫垯
-  REPAIR_FAULT_TYPE = 'repair_fault_type', // 鎶ヤ慨鐘舵��
+  REPAIR_FAULT_TYPE = 'repair_fault_type', // 鏁呴殰绫诲埆
   REPAIR_RECORD_HANDLE = 'repair_record_handle', // 缁翠慨璁板綍鎿嶄綔
   REPAIR_REQ_STATUS = 'repair_req_status', // 鎶ヤ慨鐘舵��
+  SPARE_INOUT_TYPE = 'spare_inout_type', // 澶囦欢鍑哄叆搴撶被鍨� 1-鍏ュ簱鍗� 2-鍑哄簱鍗�
   REPAIR_REQ_TYPE = 'repair_req_type', // 鎶ヤ慨绫诲瀷
   REPAIR_RES_STATUS = 'repair_res_status', // 缁翠慨鐘舵��
   REPAIR_URGENCY_LEVEL = 'repair_urgency_level', // 鎶ヤ慨绱ф�ョ▼搴�
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
index 847160d..ea61622 100644
--- a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
@@ -151,5 +151,14 @@
         String Y = "1"; // 宸插畬鎴�
     }
 
+    /**
+     *鐐规璁板綍鐘舵��
+     */
+    String EIMS_INSPECT_STATUS = "eims_inspect_status";
+    interface EIMS_INSPECT_STATUS_DETAIL {
+        String N = "0";// 鏈偣妫�
+        String Y = "1"; // 宸茬偣妫�
+    }
+
 
 }
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/SpareTypeService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/SpareTypeService.java
new file mode 100644
index 0000000..66318a0
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/SpareTypeService.java
@@ -0,0 +1,11 @@
+package org.dromara.common.core.service;
+
+public interface SpareTypeService {
+    /**
+     * 閫氳繃澶囦欢绫诲瀷ID鏌ヨ澶囦欢绫诲瀷鍚嶇О
+     *
+     * @param spareTypeIds 澶囦欢绫诲瀷ID涓查�楀彿鍒嗛殧
+     * @return 澶囦欢绫诲瀷鍚嶇О涓查�楀彿鍒嗛殧
+     */
+    String selectSpareTypeNameByIds(String spareTypeIds);
+}
diff --git a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
index 5e300da..8af9b82 100644
--- a/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
+++ b/eims/ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java
@@ -345,6 +345,17 @@
     }
 
     /**
+     * 寮�鍚簡鐗堟湰鎺у埗锛宮inio涓繚鐣欏師鏂囦欢鍚�
+     * @param data
+     * @param suffix
+     * @param fileName
+     * @return
+     */
+    public UploadResult uploadSuffix(byte[] data, String suffix,String fileName) {
+        return upload(new ByteArrayInputStream(data), getDatePath(fileName), Long.valueOf(data.length), FileUtils.getMimeType(suffix));
+    }
+
+    /**
      * 涓婁紶 InputStream 鍒� Amazon S3锛屼娇鐢ㄦ寚瀹氱殑鍚庣紑鏋勯�犲璞¢敭銆�
      *
      * @param inputStream 瑕佷笂浼犵殑杈撳叆娴�
@@ -477,6 +488,15 @@
         return path + suffix;
     }
 
+    public String getDatePath(String fileName) {
+        // 鐢熸垚鏃ユ湡璺緞
+        String datePath = DateUtils.datePath();
+        String timestamp  = DateUtils.dateTimeNow();
+        String suffix = StringUtils.substring(fileName, fileName.lastIndexOf("."), fileName.length());
+        String file = StringUtils.substring(fileName,0, fileName.lastIndexOf("."));
+        return datePath + StringUtils.SLASH + file +  "_" + timestamp +   suffix;
+    }
+
     /**
      * 绉婚櫎璺緞涓殑鍩虹URL閮ㄥ垎锛屽緱鍒扮浉瀵硅矾寰�
      *
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
index 697c3c1..fef87a0 100644
--- a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java
@@ -35,7 +35,7 @@
     /**
      * 璁惧绫诲瀷鍚嶇Оid杞悕绉�
      */
-    String EQU_YPE_ID_TO_NAME = "equ_type_id_to_name";
+    String EQU_TYPE_ID_TO_NAME = "equ_type_id_to_name";
     /**
      * 璁惧鍚嶇Оid杞悕绉�
      */
@@ -65,4 +65,10 @@
      */
     String MAINT_ORDER_ID_TO_CODE = "maint_order_id_to_code";
 
+
+    /**
+     * 澶囦欢绫诲瀷id杞琻ame
+     */
+    String SPARE_TYPE_ID_TO_NAME = "spare_type_id_to_name";
+
 }
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java
index e2fef3c..5554192 100644
--- a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/EquTypeNameTranslationImpl.java
@@ -1,7 +1,6 @@
 package org.dromara.common.translation.core.impl;
 
 import lombok.AllArgsConstructor;
-import org.dromara.common.core.service.DeptService;
 import org.dromara.common.core.service.EquTypeService;
 import org.dromara.common.translation.annotation.TranslationType;
 import org.dromara.common.translation.constant.TransConstant;
@@ -13,7 +12,7 @@
  * @author zhuguifei
  */
 @AllArgsConstructor
-@TranslationType(type = TransConstant.EQU_YPE_ID_TO_NAME)
+@TranslationType(type = TransConstant.EQU_TYPE_ID_TO_NAME)
 public class EquTypeNameTranslationImpl implements TranslationInterface<String> {
 
     private final EquTypeService equTypeService;
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/SpareTypeNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/SpareTypeNameTranslationImpl.java
new file mode 100644
index 0000000..037201e
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/SpareTypeNameTranslationImpl.java
@@ -0,0 +1,30 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.EquTypeService;
+import org.dromara.common.core.service.SpareTypeService;
+import org.dromara.common.translation.annotation.TranslationType;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.common.translation.core.TranslationInterface;
+
+/**
+ * 澶囦欢绫诲瀷缈昏瘧瀹炵幇
+ *
+ * @author zhuguifei
+ */
+@AllArgsConstructor
+@TranslationType(type = TransConstant.SPARE_TYPE_ID_TO_NAME)
+public class SpareTypeNameTranslationImpl implements TranslationInterface<String> {
+
+    private final SpareTypeService spareTypeService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String ids) {
+            return spareTypeService.selectSpareTypeNameByIds(ids);
+        } else if (key instanceof Long id) {
+            return spareTypeService.selectSpareTypeNameByIds(id.toString());
+        }
+        return null;
+    }
+}
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
index fb76424..9d346a2 100644
--- a/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -11,3 +11,4 @@
 org.dromara.common.translation.core.impl.RepairReqCodeTranslationImpl
 org.dromara.common.translation.core.impl.RepairResCodeTranslationImpl
 org.dromara.common.translation.core.impl.MaintOrderCodeTranslationImpl
+org.dromara.common.translation.core.impl.SpareTypeNameTranslationImpl
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFaultKnowController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFaultKnowController.java
new file mode 100644
index 0000000..9fa2230
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFaultKnowController.java
@@ -0,0 +1,105 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.EimsFaultKnowVo;
+import org.dromara.eims.domain.bo.EimsFaultKnowBo;
+import org.dromara.eims.service.IEimsFaultKnowService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 鏁呴殰鐭ヨ瘑
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/faultKnow")
+public class EimsFaultKnowController extends BaseController {
+
+    private final IEimsFaultKnowService eimsFaultKnowService;
+
+    /**
+     * 鏌ヨ鏁呴殰鐭ヨ瘑鍒楄〃
+     */
+    @SaCheckPermission("eims:faultKnow:list")
+    @GetMapping("/list")
+    public TableDataInfo<EimsFaultKnowVo> list(EimsFaultKnowBo bo, PageQuery pageQuery) {
+        return eimsFaultKnowService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭鏁呴殰鐭ヨ瘑鍒楄〃
+     */
+    @SaCheckPermission("eims:faultKnow:export")
+    @Log(title = "鏁呴殰鐭ヨ瘑", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsFaultKnowBo bo, HttpServletResponse response) {
+        List<EimsFaultKnowVo> list = eimsFaultKnowService.queryList(bo);
+        ExcelUtil.exportExcel(list, "鏁呴殰鐭ヨ瘑", EimsFaultKnowVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇鏁呴殰鐭ヨ瘑璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:faultKnow:query")
+    @GetMapping("/{id}")
+    public R<EimsFaultKnowVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsFaultKnowService.queryById(id));
+    }
+
+    /**
+     * 鏂板鏁呴殰鐭ヨ瘑
+     */
+    @SaCheckPermission("eims:faultKnow:add")
+    @Log(title = "鏁呴殰鐭ヨ瘑", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsFaultKnowBo bo) {
+        return toAjax(eimsFaultKnowService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼鏁呴殰鐭ヨ瘑
+     */
+    @SaCheckPermission("eims:faultKnow:edit")
+    @Log(title = "鏁呴殰鐭ヨ瘑", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsFaultKnowBo bo) {
+        return toAjax(eimsFaultKnowService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎鏁呴殰鐭ヨ瘑
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:faultKnow:remove")
+    @Log(title = "鏁呴殰鐭ヨ瘑", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsFaultKnowService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareController.java
new file mode 100644
index 0000000..e030bc3
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareController.java
@@ -0,0 +1,105 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.EimsSpareVo;
+import org.dromara.eims.domain.bo.EimsSpareBo;
+import org.dromara.eims.service.IEimsSpareService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 澶囦欢鍙拌处
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/spare")
+public class EimsSpareController extends BaseController {
+
+    private final IEimsSpareService eimsSpareService;
+
+    /**
+     * 鏌ヨ澶囦欢鍙拌处鍒楄〃
+     */
+    @SaCheckPermission("eims:spare:list")
+    @GetMapping("/list")
+    public TableDataInfo<EimsSpareVo> list(EimsSpareBo bo, PageQuery pageQuery) {
+        return eimsSpareService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭澶囦欢鍙拌处鍒楄〃
+     */
+    @SaCheckPermission("eims:spare:export")
+    @Log(title = "澶囦欢鍙拌处", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsSpareBo bo, HttpServletResponse response) {
+        List<EimsSpareVo> list = eimsSpareService.queryList(bo);
+        ExcelUtil.exportExcel(list, "澶囦欢鍙拌处", EimsSpareVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇澶囦欢鍙拌处璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:spare:query")
+    @GetMapping("/{id}")
+    public R<EimsSpareVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsSpareService.queryById(id));
+    }
+
+    /**
+     * 鏂板澶囦欢鍙拌处
+     */
+    @SaCheckPermission("eims:spare:add")
+    @Log(title = "澶囦欢鍙拌处", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsSpareBo bo) {
+        return toAjax(eimsSpareService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼澶囦欢鍙拌处
+     */
+    @SaCheckPermission("eims:spare:edit")
+    @Log(title = "澶囦欢鍙拌处", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsSpareBo bo) {
+        return toAjax(eimsSpareService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎澶囦欢鍙拌处
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:spare:remove")
+    @Log(title = "澶囦欢鍙拌处", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsSpareService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareInoutController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareInoutController.java
new file mode 100644
index 0000000..f0f8c34
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareInoutController.java
@@ -0,0 +1,105 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.EimsSpareInoutVo;
+import org.dromara.eims.domain.bo.EimsSpareInoutBo;
+import org.dromara.eims.service.IEimsSpareInoutService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 澶囦欢鍑哄叆搴�
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/spareInout")
+public class EimsSpareInoutController extends BaseController {
+
+    private final IEimsSpareInoutService eimsSpareInoutService;
+
+    /**
+     * 鏌ヨ澶囦欢鍑哄叆搴撳垪琛�
+     */
+    @SaCheckPermission("eims:spareInout:list")
+    @GetMapping("/list")
+    public TableDataInfo<EimsSpareInoutVo> list(EimsSpareInoutBo bo, PageQuery pageQuery) {
+        return eimsSpareInoutService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭澶囦欢鍑哄叆搴撳垪琛�
+     */
+    @SaCheckPermission("eims:spareInout:export")
+    @Log(title = "澶囦欢鍑哄叆搴�", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsSpareInoutBo bo, HttpServletResponse response) {
+        List<EimsSpareInoutVo> list = eimsSpareInoutService.queryList(bo);
+        ExcelUtil.exportExcel(list, "澶囦欢鍑哄叆搴�", EimsSpareInoutVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇澶囦欢鍑哄叆搴撹缁嗕俊鎭�
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:spareInout:query")
+    @GetMapping("/{id}")
+    public R<EimsSpareInoutVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsSpareInoutService.queryById(id));
+    }
+
+    /**
+     * 鏂板澶囦欢鍑哄叆搴�
+     */
+    @SaCheckPermission("eims:spareInout:add")
+    @Log(title = "澶囦欢鍑哄叆搴�", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsSpareInoutBo bo) {
+        return toAjax(eimsSpareInoutService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼澶囦欢鍑哄叆搴�
+     */
+    @SaCheckPermission("eims:spareInout:edit")
+    @Log(title = "澶囦欢鍑哄叆搴�", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsSpareInoutBo bo) {
+        return toAjax(eimsSpareInoutService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎澶囦欢鍑哄叆搴�
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:spareInout:remove")
+    @Log(title = "澶囦欢鍑哄叆搴�", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsSpareInoutService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareTypeController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareTypeController.java
new file mode 100644
index 0000000..ed94469
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsSpareTypeController.java
@@ -0,0 +1,126 @@
+package org.dromara.eims.controller;
+
+import java.util.List;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.eims.domain.bo.EimsEquTypeBo;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.eims.domain.vo.EimsSpareTypeVo;
+import org.dromara.eims.domain.bo.EimsSpareTypeBo;
+import org.dromara.eims.service.IEimsSpareTypeService;
+
+/**
+ * 澶囦欢绫诲瀷
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/spareType")
+public class EimsSpareTypeController extends BaseController {
+
+    private final IEimsSpareTypeService eimsSpareTypeService;
+
+    /**
+     * 鏌ヨ澶囦欢绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:spareType:list")
+    @GetMapping("/list")
+    public R<List<EimsSpareTypeVo>> list(EimsSpareTypeBo bo) {
+        List<EimsSpareTypeVo> list = eimsSpareTypeService.queryList(bo);
+        return R.ok(list);
+    }
+
+    /**
+     * 鑾峰彇璁惧绫诲瀷鏍戝垪琛�
+     */
+    @SaCheckPermission("eims:spareType:list")
+    @GetMapping("/tree")
+    public R<List<Tree<Long>>> spareTypeTree(EimsSpareTypeBo bo) {
+        return R.ok(eimsSpareTypeService.selectSpareTypeTreeList(bo));
+    }
+
+    /**
+     * 瀵煎嚭澶囦欢绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:spareType:export")
+    @Log(title = "澶囦欢绫诲瀷", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsSpareTypeBo bo, HttpServletResponse response) {
+        List<EimsSpareTypeVo> list = eimsSpareTypeService.queryList(bo);
+        ExcelUtil.exportExcel(list, "澶囦欢绫诲瀷", EimsSpareTypeVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇澶囦欢绫诲瀷璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:spareType:query")
+    @GetMapping("/{id}")
+    public R<EimsSpareTypeVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsSpareTypeService.queryById(id));
+    }
+
+    /**
+     * 鏂板澶囦欢绫诲瀷
+     */
+    @SaCheckPermission("eims:spareType:add")
+    @Log(title = "澶囦欢绫诲瀷", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsSpareTypeBo bo) {
+        return toAjax(eimsSpareTypeService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼澶囦欢绫诲瀷
+     */
+    @SaCheckPermission("eims:spareType:edit")
+    @Log(title = "澶囦欢绫诲瀷", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsSpareTypeBo bo) {
+        return toAjax(eimsSpareTypeService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎澶囦欢绫诲瀷
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:spareType:remove")
+    @Log(title = "澶囦欢绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+
+        if (ids == null || ids.length == 0) {
+            return R.warn("璇烽�夋嫨闇�瑕佸垹闄ょ殑鏁版嵁");
+        }
+        for (int i = 0; i < ids.length; i++) {
+            if (eimsSpareTypeService.hasChildBySpareTypeId(ids[i])) {
+                return R.warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+            }
+        }
+
+        return toAjax(eimsSpareTypeService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFaultKnow.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFaultKnow.java
new file mode 100644
index 0000000..f56d84d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFaultKnow.java
@@ -0,0 +1,76 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 鏁呴殰鐭ヨ瘑瀵硅薄 eims_fault_know
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_fault_know")
+public class EimsFaultKnow extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 璁惧id
+     */
+    private Long equId;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private Long equType;
+
+    /**
+     * 璁惧閮ㄤ綅(瀛楀吀)
+     */
+    private String equPart;
+
+    /**
+     * 鐭ヨ瘑缂栫爜
+     */
+    private String faultCode;
+
+    /**
+     * 鏁呴殰绫诲埆(瀛楀吀)
+     */
+    private String faultType;
+
+    /**
+     * 鏁呴殰鍘熷洜(瀛楀吀)
+     */
+    private String faultReason;
+
+    /**
+     * 鎶ヤ慨鎻忚堪
+     */
+    private String reqDesc;
+
+    /**
+     * 澶勭悊鎺柦
+     */
+    private String resHandle;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpare.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpare.java
new file mode 100644
index 0000000..b4d18cb
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpare.java
@@ -0,0 +1,114 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+
+import java.io.Serial;
+import java.math.BigDecimal;
+
+/**
+ * 澶囦欢鍙拌处瀵硅薄 eims_spare
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_spare")
+public class EimsSpare extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 绫诲瀷
+     */
+    private Long type;
+
+    /**
+     * 澶囦欢鍚嶇О
+     */
+    private String name;
+
+    /**
+     * 澶囦欢缂栫爜
+     */
+    private String code;
+
+    /**
+     * 澶囦欢鍥剧墖
+     */
+    private Long img;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 渚涘簲鍟�
+     */
+    private String supplier;
+
+    /**
+     * 璁¢噺鍗曚綅锛堝瓧鍏革級
+     */
+    private String unit;
+
+    /**
+     * 鍙傝�冧环鏍�
+     */
+    private BigDecimal referPrice;
+
+    /**
+     * 搴撳瓨涓婇檺
+     */
+    private Long upperStock;
+
+    /**
+     * 搴撳瓨涓嬮檺
+     */
+    private Long lowerStock;
+
+    /**
+     * 瀹為檯搴撳瓨
+     */
+    private Long actualStock;
+
+    /**
+     * 搴撳瓨閲戦
+     */
+    private BigDecimal stockAmount;
+
+    /**
+     * 鏇存崲鍛ㄦ湡
+     */
+    private Long replaceCycle;
+
+    /**
+     * 鏇存崲鍛ㄦ湡鍗曚綅锛堝瓧鍏革級
+     */
+    private String cycleUnit;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareInout.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareInout.java
new file mode 100644
index 0000000..15bdc8e
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareInout.java
@@ -0,0 +1,70 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serial;
+
+/**
+ * 澶囦欢鍑哄叆搴撳璞� eims_spare_inout
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_spare_inout")
+public class EimsSpareInout extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 鍗曞彿
+     */
+    private String orderCode;
+
+    /**
+     * 鍗曞彿鏃ユ湡
+     */
+    private Date orderTime;
+
+    /**
+     * 缁忓姙浜�
+     */
+    private Long chargeUser;
+    private Long chargeDept;
+
+
+    /**
+     * 宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀
+     */
+    private String type;
+
+    /**
+     * 鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢
+     */
+    private String partnerName;
+
+    /**
+     * 鍏宠仈鍗曞彿锛堝-缁翠慨鍗曪級
+     */
+    private String associatedOrder;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareType.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareType.java
new file mode 100644
index 0000000..6b49780
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsSpareType.java
@@ -0,0 +1,71 @@
+package org.dromara.eims.domain;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serial;
+
+/**
+ * 澶囦欢绫诲瀷瀵硅薄 eims_spare_type
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_spare_type")
+public class EimsSpareType extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFaultKnowBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFaultKnowBo.java
new file mode 100644
index 0000000..66debd8
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFaultKnowBo.java
@@ -0,0 +1,94 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsFaultKnow;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 鏁呴殰鐭ヨ瘑涓氬姟瀵硅薄 eims_fault_know
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsFaultKnow.class, reverseConvertGenerate = false)
+public class EimsFaultKnowBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 璁惧id
+     */
+    @NotNull(message = "璁惧id涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private Long equId;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    private Long equType;
+
+    /**
+     * 璁惧閮ㄤ綅(瀛楀吀)
+     */
+    private String equPart;
+
+    /**
+     * 鐭ヨ瘑缂栫爜
+     */
+    @NotBlank(message = "鐭ヨ瘑缂栫爜涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String faultCode;
+
+    /**
+     * 鏁呴殰绫诲埆(瀛楀吀)
+     */
+    private String faultType;
+
+    /**
+     * 鏁呴殰鍘熷洜(瀛楀吀)
+     */
+    private String faultReason;
+
+    /**
+     * 鎶ヤ慨鎻忚堪
+     */
+    private String reqDesc;
+
+    /**
+     * 澶勭悊鎺柦
+     */
+    private String resHandle;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+    //鍏宠仈琛ㄥ瓧娈�
+    /**
+     * 璁惧鍚嶇О
+     */
+    private String equName;
+
+    /**
+     * 璁惧璧勪骇缂栧彿
+     */
+    private String assetNo;
+
+    /**
+     * 璁惧绫诲瀷id
+     */
+    private Long equTypeId;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareBo.java
new file mode 100644
index 0000000..daed6f9
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareBo.java
@@ -0,0 +1,117 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsSpare;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+
+import java.math.BigDecimal;
+
+/**
+ * 澶囦欢鍙拌处涓氬姟瀵硅薄 eims_spare
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsSpare.class, reverseConvertGenerate = false)
+public class EimsSpareBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 绫诲瀷
+     */
+    @NotNull(message = "绫诲瀷涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private Long type;
+
+    /**
+     * 澶囦欢鍚嶇О
+     */
+    @NotBlank(message = "澶囦欢鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String name;
+
+    /**
+     * 澶囦欢缂栫爜
+     */
+    @NotBlank(message = "澶囦欢缂栫爜涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String code;
+
+    /**
+     * 澶囦欢鍥剧墖
+     */
+    private Long img;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 渚涘簲鍟�
+     */
+    private String supplier;
+
+    /**
+     * 璁¢噺鍗曚綅锛堝瓧鍏革級
+     */
+    private String unit;
+
+    /**
+     * 鍙傝�冧环鏍�
+     */
+    private BigDecimal referPrice;
+
+    /**
+     * 搴撳瓨涓婇檺
+     */
+    private Long upperStock;
+
+    /**
+     * 搴撳瓨涓嬮檺
+     */
+    private Long lowerStock;
+
+    /**
+     * 瀹為檯搴撳瓨
+     */
+    private Long actualStock;
+
+    /**
+     * 搴撳瓨閲戦
+     */
+    private BigDecimal stockAmount;
+
+    /**
+     * 鏇存崲鍛ㄦ湡
+     */
+    private Long replaceCycle;
+
+    /**
+     * 鏇存崲鍛ㄦ湡鍗曚綅锛堝瓧鍏革級
+     */
+    private String cycleUnit;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareInoutBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareInoutBo.java
new file mode 100644
index 0000000..4af19e2
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareInoutBo.java
@@ -0,0 +1,73 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsSpareInout;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+/**
+ * 澶囦欢鍑哄叆搴撲笟鍔″璞� eims_spare_inout
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsSpareInout.class, reverseConvertGenerate = false)
+public class EimsSpareInoutBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 鍗曞彿
+     */
+    @NotBlank(message = "鍗曞彿涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String orderCode;
+
+    /**
+     * 鍗曞彿鏃ユ湡
+     */
+    @NotNull(message = "鍗曞彿鏃ユ湡涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private Date orderTime;
+
+    /**
+     * 缁忓姙浜�
+     */
+    @NotNull(message = "缁忓姙浜轰笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private Long chargeUser;
+    private Long chargeDept;
+
+    /**
+     * 宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀
+     */
+    @NotBlank(message = "宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String type;
+
+    /**
+     * 鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢
+     */
+    @NotBlank(message = "鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String partnerName;
+
+    /**
+     * 鍏宠仈鍗曞彿锛堝-缁翠慨鍗曪級
+     */
+    private String associatedOrder;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareTypeBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareTypeBo.java
new file mode 100644
index 0000000..234d76a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsSpareTypeBo.java
@@ -0,0 +1,74 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsSpareType;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+
+/**
+ * 澶囦欢绫诲瀷涓氬姟瀵硅薄 eims_spare_type
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsSpareType.class, reverseConvertGenerate = false)
+public class EimsSpareTypeBo extends BaseEntity {
+
+    /**
+     * 
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    @NotBlank(message = "绫诲瀷鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    @NotBlank(message = "绫诲瀷缂栫爜涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    @NotBlank(message = "鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛変笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @NotBlank(message = "鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛変笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquVo.java
index 9df4c1a..528a795 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquVo.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquVo.java
@@ -166,7 +166,7 @@
      * 璁惧绫诲瀷鍚嶇О
      */
     //@ExcelProperty(value = "璁惧绫诲瀷")
-    @Translation(type = TransConstant.EQU_YPE_ID_TO_NAME, mapper = "equTypeId")
+    @Translation(type = TransConstant.EQU_TYPE_ID_TO_NAME, mapper = "equTypeId")
     private String equTypeName;
 
 
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFaultKnowVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFaultKnowVo.java
new file mode 100644
index 0000000..0b273ae
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFaultKnowVo.java
@@ -0,0 +1,100 @@
+package org.dromara.eims.domain.vo;
+
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.eims.domain.EimsFaultKnow;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 鏁呴殰鐭ヨ瘑瑙嗗浘瀵硅薄 eims_fault_know
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsFaultKnow.class)
+public class EimsFaultKnowVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 璁惧id
+     */
+    @ExcelProperty(value = "璁惧id")
+    private Long equId;
+    @Translation(type = TransConstant.EQU_ID_TO_NAME, mapper = "equId")
+    private String equName;
+    private String assetNo;
+
+    /**
+     * 璁惧绫诲瀷
+     */
+    @ExcelProperty(value = "璁惧绫诲瀷", converter = ExcelDictConvert.class)
+    private Long equType;
+
+    private String equTypeName;
+
+    /**
+     * 璁惧閮ㄤ綅(瀛楀吀)
+     */
+    @ExcelProperty(value = "璁惧閮ㄤ綅(瀛楀吀)")
+    private String equPart;
+
+    /**
+     * 鐭ヨ瘑缂栫爜
+     */
+    @ExcelProperty(value = "鐭ヨ瘑缂栫爜")
+    private String faultCode;
+
+    /**
+     * 鏁呴殰绫诲埆(瀛楀吀)
+     */
+    @ExcelProperty(value = "鏁呴殰绫诲埆(瀛楀吀)", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "repair_fault_type")
+    private String faultType;
+
+    /**
+     * 鏁呴殰鍘熷洜(瀛楀吀)
+     */
+    @ExcelProperty(value = "鏁呴殰鍘熷洜(瀛楀吀)")
+    private String faultReason;
+
+    /**
+     * 鎶ヤ慨鎻忚堪
+     */
+    @ExcelProperty(value = "鎶ヤ慨鎻忚堪")
+    private String reqDesc;
+
+    /**
+     * 澶勭悊鎺柦
+     */
+    @ExcelProperty(value = "澶勭悊鎺柦")
+    private String resHandle;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareInoutVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareInoutVo.java
new file mode 100644
index 0000000..12c8120
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareInoutVo.java
@@ -0,0 +1,91 @@
+package org.dromara.eims.domain.vo;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.eims.domain.EimsSpareInout;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 澶囦欢鍑哄叆搴撹鍥惧璞� eims_spare_inout
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsSpareInout.class)
+public class EimsSpareInoutVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 鍗曞彿
+     */
+    @ExcelProperty(value = "鍗曞彿")
+    private String orderCode;
+
+    /**
+     * 鍗曞彿鏃ユ湡
+     */
+    @ExcelProperty(value = "鍗曞彿鏃ユ湡")
+    private Date orderTime;
+
+    /**
+     * 缁忓姙浜�
+     */
+    @ExcelProperty(value = "缁忓姙浜�")
+    private Long chargeUser;
+    private Long chargeDept;
+    @Translation(type = TransConstant.USER_ID_TO_NICKNAME, mapper = "chargeUser")
+    private String chargeUserName;
+    @Translation(type = TransConstant.DEPT_ID_TO_NAME, mapper = "chargeDept")
+    private String chargeDeptName;
+
+    /**
+     * 宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀
+     */
+    @ExcelProperty(value = "宸ュ崟绫诲瀷", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "spare_inout_type")
+    private String type;
+
+    /**
+     * 鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢
+     */
+    @ExcelProperty(value = "鍑哄簱瀹㈡埛鍚嶇О鎴栧叆搴撲緵搴斿晢")
+    private String partnerName;
+
+    /**
+     * 鍏宠仈鍗曞彿锛堝-缁翠慨鍗曪級
+     */
+    @ExcelProperty(value = "鍏宠仈鍗曞彿", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "濡�=-缁翠慨鍗�")
+    private String associatedOrder;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareTypeVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareTypeVo.java
new file mode 100644
index 0000000..90cb938
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareTypeVo.java
@@ -0,0 +1,88 @@
+package org.dromara.eims.domain.vo;
+
+import org.dromara.eims.domain.EimsSpareType;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 澶囦欢绫诲瀷瑙嗗浘瀵硅薄 eims_spare_type
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsSpareType.class)
+public class EimsSpareTypeVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 绫诲瀷鍚嶇О
+     */
+    @ExcelProperty(value = "绫诲瀷鍚嶇О")
+    private String typeName;
+
+    /**
+     * 绫诲瀷缂栫爜
+     */
+    @ExcelProperty(value = "绫诲瀷缂栫爜")
+    private String typeCode;
+
+    /**
+     * 鐖秈d
+     */
+    @ExcelProperty(value = "鐖秈d")
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @ExcelProperty(value = "鏄剧ず椤哄簭")
+    private Long orderNum;
+
+    /**
+     * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+     */
+    @ExcelProperty(value = "鑿滃崟绫诲瀷", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "M=鐩綍,C=鑿滃崟,F=鎸夐挳")
+    private String menuType;
+
+    /**
+     * 鑿滃崟鍥炬爣
+     */
+    @ExcelProperty(value = "鑿滃崟鍥炬爣")
+    private String icon;
+
+    /**
+     * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+     */
+    @ExcelProperty(value = "鑿滃崟鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareVo.java
new file mode 100644
index 0000000..2a47785
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsSpareVo.java
@@ -0,0 +1,147 @@
+package org.dromara.eims.domain.vo;
+
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.eims.domain.EimsSpare;
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+
+/**
+ * 澶囦欢鍙拌处瑙嗗浘瀵硅薄 eims_spare
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsSpare.class)
+public class EimsSpareVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 绫诲瀷
+     */
+    @ExcelProperty(value = "绫诲瀷")
+    private Long type;
+
+    @Translation(type = TransConstant.SPARE_TYPE_ID_TO_NAME, mapper = "type")
+    private String typeName;
+
+    /**
+     * 澶囦欢鍚嶇О
+     */
+    @ExcelProperty(value = "澶囦欢鍚嶇О")
+    private String name;
+
+    /**
+     * 澶囦欢缂栫爜
+     */
+    @ExcelProperty(value = "澶囦欢缂栫爜")
+    private String code;
+
+    /**
+     * 澶囦欢鍥剧墖
+     */
+    @ExcelProperty(value = "澶囦欢鍥剧墖")
+    private Long img;
+
+    /**
+     * 澶囦欢鍥剧墖Url
+     */
+    @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "img")
+    private String imgUrl;
+    /**
+     * 鍨嬪彿
+     */
+    @ExcelProperty(value = "鍨嬪彿")
+    private String modelNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    @ExcelProperty(value = "鍒堕�犲晢")
+    private String madeIn;
+
+    /**
+     * 渚涘簲鍟�
+     */
+    @ExcelProperty(value = "渚涘簲鍟�")
+    private String supplier;
+
+    /**
+     * 璁¢噺鍗曚綅锛堝瓧鍏革級
+     */
+    @ExcelProperty(value = "璁¢噺鍗曚綅", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "eims_spare_unit")
+    private String unit;
+
+    /**
+     * 鍙傝�冧环鏍�
+     */
+    @ExcelProperty(value = "鍙傝�冧环鏍�")
+    private BigDecimal referPrice;
+
+    /**
+     * 搴撳瓨涓婇檺
+     */
+    @ExcelProperty(value = "搴撳瓨涓婇檺")
+    private Long upperStock;
+
+    /**
+     * 搴撳瓨涓嬮檺
+     */
+    @ExcelProperty(value = "搴撳瓨涓嬮檺")
+    private Long lowerStock;
+
+    /**
+     * 瀹為檯搴撳瓨
+     */
+    @ExcelProperty(value = "瀹為檯搴撳瓨")
+    private Long actualStock;
+
+    /**
+     * 搴撳瓨閲戦
+     */
+    @ExcelProperty(value = "搴撳瓨閲戦")
+    private BigDecimal stockAmount;
+
+    /**
+     * 鏇存崲鍛ㄦ湡
+     */
+    @ExcelProperty(value = "鏇存崲鍛ㄦ湡")
+    private Long replaceCycle;
+
+    /**
+     * 鏇存崲鍛ㄦ湡鍗曚綅锛堝瓧鍏革級
+     */
+    @ExcelProperty(value = "鏇存崲鍛ㄦ湡鍗曚綅", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "maint_cycle_unit")
+    private String cycleUnit;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/InspectPlanToRecordJob.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/InspectPlanToRecordJob.java
new file mode 100644
index 0000000..aa2096a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/job/InspectPlanToRecordJob.java
@@ -0,0 +1,124 @@
+package org.dromara.eims.job;
+
+import com.aizuda.snailjob.client.job.core.annotation.JobExecutor;
+import com.aizuda.snailjob.client.job.core.dto.JobArgs;
+import com.aizuda.snailjob.client.model.ExecuteResult;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
+import org.dromara.common.core.constant.DictConstants;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.eims.domain.EimsInspectPlan;
+import org.dromara.eims.domain.EimsInspectRecord;
+import org.dromara.eims.domain.EimsMaintOrder;
+import org.dromara.eims.domain.EimsMaintPlan;
+import org.dromara.eims.domain.vo.EimsInspectPlanVo;
+import org.dromara.eims.domain.vo.EimsMaintPlanVo;
+import org.dromara.eims.mapper.EimsInspectPlanMapper;
+import org.dromara.eims.mapper.EimsInspectRecordMapper;
+import org.dromara.eims.mapper.EimsMaintOrderMapper;
+import org.dromara.eims.mapper.EimsMaintPlanMapper;
+import org.dromara.eims.service.IGenerateCodeService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.List;
+
+@Component
+@RequiredArgsConstructor
+@JobExecutor(name = "inspectPlanToRecordJob")
+public class InspectPlanToRecordJob {
+    private final EimsInspectRecordMapper recordMapper;
+
+
+    private final EimsInspectPlanMapper planMapper;
+
+    private final IGenerateCodeService codeService;
+
+
+    @SneakyThrows
+    @Transactional(rollbackFor = Exception.class)
+    public ExecuteResult jobExecute(JobArgs jobArgs) {
+        // 鑾峰彇浠婂ぉ鏃ユ湡
+
+        Date today = new Date();
+        LambdaQueryWrapper<EimsInspectPlan> planBoQueryWrapper = Wrappers.lambdaQuery();
+        // 鏌ヨ鍚敤鐨勭偣妫�璁″垝
+        planBoQueryWrapper.eq(EimsInspectPlan::getStatus, DictConstants.SYS_NORMAL_DISABLE_DETAIL.NORMAL);
+        // 杩囨护娌℃湁涓嬫杩愯鏃堕棿
+        planBoQueryWrapper.isNotNull(EimsInspectPlan::getInspNextTime);
+        // 杩囨护娌℃湁鐐规鍛ㄦ湡鐨勬暟鎹�
+        planBoQueryWrapper.isNotNull(EimsInspectPlan::getInspCycle);
+        planBoQueryWrapper.isNotNull(EimsInspectPlan::getInspCycleUnit);
+
+        List<EimsInspectPlanVo> planVoList = planMapper.selectVoList(planBoQueryWrapper);
+        for (int i = 0; i < planVoList.size(); i++) {
+            EimsInspectPlanVo planVo = planVoList.get(i);
+            // 鐐规璁″垝add鐨勬椂鍊欎細鑷姩鐢熸垚涓嬫杩愯鏃堕棿
+            Date oldNext = planVo.getInspNextTime();
+            int day = DateUtils.differentDays(today, oldNext);
+            // 濡傛灉璁″垝鐢熸垚鐐规鏃ユ湡澶т簬浠婂ぉ鍒欎笉鐢熸垚鐐规璁板綍
+            if (day >= 1) {
+                continue;
+            }
+
+            // 璁$畻鐢熸垚鐐规璁板綍鏃堕棿
+            Long inspCycle = planVo.getInspCycle();
+            Date newNext = null;
+            String inspCycleUnit = planVo.getInspCycleUnit();
+            switch (inspCycleUnit) {
+                case DictConstants.MAINT_CYCLE_UNIT_DETAIL.DAY:
+                    newNext = DateUtils.addDays(oldNext, inspCycle.intValue());
+                    break;
+                case DictConstants.MAINT_CYCLE_UNIT_DETAIL.WEEK:
+
+                    newNext = DateUtils.addWeeks(oldNext, inspCycle.intValue());
+
+                    break;
+                case DictConstants.MAINT_CYCLE_UNIT_DETAIL.MONTH:
+
+                    newNext = DateUtils.addMonths(oldNext, inspCycle.intValue());
+
+                    break;
+                case DictConstants.MAINT_CYCLE_UNIT_DETAIL.SEASON:
+                    newNext = DateUtils.addMonths(oldNext, inspCycle.intValue() * 3);
+
+                    break;
+                case DictConstants.MAINT_CYCLE_UNIT_DETAIL.YEAR:
+
+                    newNext = DateUtils.addYears(oldNext, inspCycle.intValue());
+
+                    break;
+            }
+
+            EimsInspectRecord record = new EimsInspectRecord();
+            record.setEquId(planVo.getEquId());
+            record.setInspDesc(planVo.getInspDesc());
+            record.setInspType(planVo.getInspType());
+            record.setInspUser(planVo.getInspUser());
+            record.setInspDept(planVo.getInspDept());
+            record.setStatus(DictConstants.EIMS_INSPECT_STATUS_DETAIL.N);
+            record.setPlanTime(oldNext);
+            record.setPlanId(planVo.getId());
+            //鐐规椤瑰悕绉�
+            record.setInspName(planVo.getInspName());
+            record.setInspCode(codeService.generateCode("DJZD"));
+            EimsInspectPlan plan = MapstructUtils.convert(planVo, EimsInspectPlan.class);
+            assert plan != null;
+            plan.setInspLastTime(oldNext);
+            plan.setInspNextTime(newNext);
+            if(plan.getInspFirstTime()==null)plan.setInspFirstTime(oldNext);
+            boolean flag = recordMapper.insert(record) > 0;
+            //TODO 鐢熸垚澶辫触锛屾坊鍔犲紓甯歌褰�
+            if (!flag) continue;
+            planMapper.updateById(plan);
+
+
+        }
+        return ExecuteResult.success("鐐规璁″垝鐢熸垚鐐规璁板綍鎴愬姛");
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFaultKnowMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFaultKnowMapper.java
new file mode 100644
index 0000000..e5dd40a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFaultKnowMapper.java
@@ -0,0 +1,23 @@
+package org.dromara.eims.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.eims.domain.EimsFaultKnow;
+import org.dromara.eims.domain.EimsInspectSt;
+import org.dromara.eims.domain.vo.EimsFaultKnowVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.eims.domain.vo.EimsInspectStVo;
+
+/**
+ * 鏁呴殰鐭ヨ瘑Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+public interface EimsFaultKnowMapper extends BaseMapperPlus<EimsFaultKnow, EimsFaultKnowVo> {
+
+    Page<EimsFaultKnowVo> selectFaultKnowList(@Param("page") Page<EimsFaultKnowVo> page, @Param(Constants.WRAPPER) Wrapper<EimsFaultKnow> queryWrapper);
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareInoutMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareInoutMapper.java
new file mode 100644
index 0000000..bffe366
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareInoutMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsSpareInout;
+import org.dromara.eims.domain.vo.EimsSpareInoutVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 澶囦欢鍑哄叆搴揗apper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+public interface EimsSpareInoutMapper extends BaseMapperPlus<EimsSpareInout, EimsSpareInoutVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareMapper.java
new file mode 100644
index 0000000..23538f2
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsSpare;
+import org.dromara.eims.domain.vo.EimsSpareVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 澶囦欢鍙拌处Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+public interface EimsSpareMapper extends BaseMapperPlus<EimsSpare, EimsSpareVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareTypeMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareTypeMapper.java
new file mode 100644
index 0000000..132931d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsSpareTypeMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsSpareType;
+import org.dromara.eims.domain.vo.EimsSpareTypeVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 澶囦欢绫诲瀷Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+public interface EimsSpareTypeMapper extends BaseMapperPlus<EimsSpareType, EimsSpareTypeVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFaultKnowService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFaultKnowService.java
new file mode 100644
index 0000000..961c26f
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFaultKnowService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import org.dromara.eims.domain.vo.EimsFaultKnowVo;
+import org.dromara.eims.domain.bo.EimsFaultKnowBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鏁呴殰鐭ヨ瘑Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+public interface IEimsFaultKnowService {
+
+    /**
+     * 鏌ヨ鏁呴殰鐭ヨ瘑
+     *
+     * @param id 涓婚敭
+     * @return 鏁呴殰鐭ヨ瘑
+     */
+    EimsFaultKnowVo queryById(Long id);
+
+    /**
+     * 鍒嗛〉鏌ヨ鏁呴殰鐭ヨ瘑鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鏁呴殰鐭ヨ瘑鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<EimsFaultKnowVo> queryPageList(EimsFaultKnowBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬晠闅滅煡璇嗗垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏁呴殰鐭ヨ瘑鍒楄〃
+     */
+    List<EimsFaultKnowVo> queryList(EimsFaultKnowBo bo);
+
+    /**
+     * 鏂板鏁呴殰鐭ヨ瘑
+     *
+     * @param bo 鏁呴殰鐭ヨ瘑
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsFaultKnowBo bo);
+
+    /**
+     * 淇敼鏁呴殰鐭ヨ瘑
+     *
+     * @param bo 鏁呴殰鐭ヨ瘑
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsFaultKnowBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゆ晠闅滅煡璇嗕俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareInoutService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareInoutService.java
new file mode 100644
index 0000000..f16e11a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareInoutService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import org.dromara.eims.domain.vo.EimsSpareInoutVo;
+import org.dromara.eims.domain.bo.EimsSpareInoutBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 澶囦欢鍑哄叆搴揝ervice鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+public interface IEimsSpareInoutService {
+
+    /**
+     * 鏌ヨ澶囦欢鍑哄叆搴�
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢鍑哄叆搴�
+     */
+    EimsSpareInoutVo queryById(Long id);
+
+    /**
+     * 鍒嗛〉鏌ヨ澶囦欢鍑哄叆搴撳垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 澶囦欢鍑哄叆搴撳垎椤靛垪琛�
+     */
+    TableDataInfo<EimsSpareInoutVo> queryPageList(EimsSpareInoutBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠跺嚭鍏ュ簱鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢鍑哄叆搴撳垪琛�
+     */
+    List<EimsSpareInoutVo> queryList(EimsSpareInoutBo bo);
+
+    /**
+     * 鏂板澶囦欢鍑哄叆搴�
+     *
+     * @param bo 澶囦欢鍑哄叆搴�
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsSpareInoutBo bo);
+
+    /**
+     * 淇敼澶囦欢鍑哄叆搴�
+     *
+     * @param bo 澶囦欢鍑哄叆搴�
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsSpareInoutBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠跺嚭鍏ュ簱淇℃伅
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareService.java
new file mode 100644
index 0000000..0569fbf
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import org.dromara.eims.domain.vo.EimsSpareVo;
+import org.dromara.eims.domain.bo.EimsSpareBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 澶囦欢鍙拌处Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+public interface IEimsSpareService {
+
+    /**
+     * 鏌ヨ澶囦欢鍙拌处
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢鍙拌处
+     */
+    EimsSpareVo queryById(Long id);
+
+    /**
+     * 鍒嗛〉鏌ヨ澶囦欢鍙拌处鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 澶囦欢鍙拌处鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<EimsSpareVo> queryPageList(EimsSpareBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠跺彴璐﹀垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢鍙拌处鍒楄〃
+     */
+    List<EimsSpareVo> queryList(EimsSpareBo bo);
+
+    /**
+     * 鏂板澶囦欢鍙拌处
+     *
+     * @param bo 澶囦欢鍙拌处
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsSpareBo bo);
+
+    /**
+     * 淇敼澶囦欢鍙拌处
+     *
+     * @param bo 澶囦欢鍙拌处
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsSpareBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠跺彴璐︿俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareTypeService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareTypeService.java
new file mode 100644
index 0000000..2d80651
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsSpareTypeService.java
@@ -0,0 +1,76 @@
+package org.dromara.eims.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import jakarta.validation.constraints.NotEmpty;
+import org.dromara.eims.domain.vo.EimsSpareTypeVo;
+import org.dromara.eims.domain.bo.EimsSpareTypeBo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 澶囦欢绫诲瀷Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+public interface IEimsSpareTypeService {
+
+    /**
+     * 鏌ヨ澶囦欢绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢绫诲瀷
+     */
+    EimsSpareTypeVo queryById(Long id);
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠剁被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢绫诲瀷鍒楄〃
+     */
+    List<EimsSpareTypeVo> queryList(EimsSpareTypeBo bo);
+
+    /**
+     * 鏂板澶囦欢绫诲瀷
+     *
+     * @param bo 澶囦欢绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsSpareTypeBo bo);
+
+    /**
+     * 淇敼澶囦欢绫诲瀷
+     *
+     * @param bo 澶囦欢绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsSpareTypeBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠剁被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 妫�鏌ユ槸鍚﹀瓨鍦ㄥ瓙椤�
+     * @param id
+     * @return
+     */
+    boolean hasChildBySpareTypeId(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") Long id);
+
+
+    /**
+     * 鑾峰彇澶囦欢绫诲瀷鏍戝垪琛�
+     *
+     * @param bo
+     * @return 鏍戝垪琛�
+     */
+    List<Tree<Long>> selectSpareTypeTreeList(EimsSpareTypeBo bo);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFaultKnowServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFaultKnowServiceImpl.java
new file mode 100644
index 0000000..48c0827
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFaultKnowServiceImpl.java
@@ -0,0 +1,191 @@
+package org.dromara.eims.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.eims.domain.EimsEquType;
+import org.dromara.eims.domain.vo.EimsEquTypeVo;
+import org.dromara.eims.mapper.EimsEquTypeMapper;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsFaultKnowBo;
+import org.dromara.eims.domain.vo.EimsFaultKnowVo;
+import org.dromara.eims.domain.EimsFaultKnow;
+import org.dromara.eims.mapper.EimsFaultKnowMapper;
+import org.dromara.eims.service.IEimsFaultKnowService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 鏁呴殰鐭ヨ瘑Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-03-18
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsFaultKnowServiceImpl implements IEimsFaultKnowService {
+
+    private final EimsFaultKnowMapper baseMapper;
+    private final EimsEquTypeMapper equTypeMapper;
+
+    /**
+     * 鏌ヨ鏁呴殰鐭ヨ瘑
+     *
+     * @param id 涓婚敭
+     * @return 鏁呴殰鐭ヨ瘑
+     */
+    @Override
+    public EimsFaultKnowVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ鏁呴殰鐭ヨ瘑鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 鏁呴殰鐭ヨ瘑鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<EimsFaultKnowVo> queryPageList(EimsFaultKnowBo bo, PageQuery pageQuery) {
+        QueryWrapper<EimsFaultKnow> qw = buildWrapper(bo);
+        Page<EimsFaultKnowVo> result = baseMapper.selectFaultKnowList(pageQuery.build(), qw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勬晠闅滅煡璇嗗垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 鏁呴殰鐭ヨ瘑鍒楄〃
+     */
+    @Override
+    public List<EimsFaultKnowVo> queryList(EimsFaultKnowBo bo) {
+        LambdaQueryWrapper<EimsFaultKnow> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsFaultKnow> buildQueryWrapper(EimsFaultKnowBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsFaultKnow> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getEquId() != null, EimsFaultKnow::getEquId, bo.getEquId());
+        lqw.eq(bo.getEquType() != null, EimsFaultKnow::getEquType, bo.getEquType());
+        lqw.eq(StringUtils.isNotBlank(bo.getEquPart()), EimsFaultKnow::getEquPart, bo.getEquPart());
+        lqw.eq(StringUtils.isNotBlank(bo.getFaultCode()), EimsFaultKnow::getFaultCode, bo.getFaultCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getFaultType()), EimsFaultKnow::getFaultType, bo.getFaultType());
+        lqw.eq(StringUtils.isNotBlank(bo.getFaultReason()), EimsFaultKnow::getFaultReason, bo.getFaultReason());
+        lqw.eq(StringUtils.isNotBlank(bo.getReqDesc()), EimsFaultKnow::getReqDesc, bo.getReqDesc());
+        lqw.eq(StringUtils.isNotBlank(bo.getResHandle()), EimsFaultKnow::getResHandle, bo.getResHandle());
+        return lqw;
+    }
+    private QueryWrapper<EimsFaultKnow> buildWrapper(EimsFaultKnowBo bo) {
+        Map<String, Object> params = bo.getParams();
+        QueryWrapper<EimsFaultKnow> qw = Wrappers.query();
+        qw.eq(bo.getEquId() != null, "fk.equ_id", bo.getEquId());
+        qw.eq(bo.getEquType() != null,"fk.equ_type", bo.getEquType());
+        qw.like(bo.getEquName() != null,"eu.equ_name", bo.getEquName());
+        qw.like(bo.getAssetNo() != null,"eu.asset_no", bo.getAssetNo());
+        qw.eq(StringUtils.isNotBlank(bo.getEquPart()), "fk.equ_part", bo.getEquPart());
+        qw.like(StringUtils.isNotBlank(bo.getFaultCode()), "fk.fault_code", bo.getFaultCode());
+        qw.eq(StringUtils.isNotBlank(bo.getFaultType()), "fk.fault_type", bo.getFaultType());
+        qw.eq(StringUtils.isNotBlank(bo.getFaultReason()), "fk.fault_reason", bo.getFaultReason());
+        qw.like(StringUtils.isNotBlank(bo.getReqDesc()),"fk.req_desc", bo.getReqDesc());
+        qw.like(StringUtils.isNotBlank(bo.getResHandle()), "fk.res_handle", bo.getResHandle());
+
+        if (bo.getEquTypeId() != null && bo.getEquTypeId() > 0) {
+            List<Long> allDescendantIds = getAllDescendantIds(bo.getEquTypeId());
+            qw.in("et.equ_type_id", allDescendantIds);
+        }
+
+
+        return qw;
+    }
+
+    /**
+     * 鏍规嵁id锛岃幏鍙栨墍鏈夊悗浠d
+     *
+     * @param rootId
+     * @return
+     */
+    public List<Long> getAllDescendantIds(Long rootId) {
+        List<Long> result = new ArrayList<>();
+        result.add(rootId);
+        collectDescendants(rootId, result);
+        return result;
+    }
+
+    private void collectDescendants(Long currentId, List<Long> collector) {
+        QueryWrapper<EimsEquType> equTypeWrapper = new QueryWrapper<>();
+        equTypeWrapper.lambda().eq(EimsEquType::getParentId, currentId);
+
+        List<EimsEquTypeVo> children = equTypeMapper.selectVoList(equTypeWrapper);
+        if (children != null && !children.isEmpty()) {
+            for (EimsEquTypeVo child : children) {
+                Long childId = child.getEquTypeId();
+                collector.add(childId);
+                collectDescendants(childId, collector);
+            }
+        }
+    }
+
+    /**
+     * 鏂板鏁呴殰鐭ヨ瘑
+     *
+     * @param bo 鏁呴殰鐭ヨ瘑
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsFaultKnowBo bo) {
+        EimsFaultKnow add = MapstructUtils.convert(bo, EimsFaultKnow.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼鏁呴殰鐭ヨ瘑
+     *
+     * @param bo 鏁呴殰鐭ヨ瘑
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsFaultKnowBo bo) {
+        EimsFaultKnow update = MapstructUtils.convert(bo, EimsFaultKnow.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsFaultKnow entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゆ晠闅滅煡璇嗕俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareInoutServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareInoutServiceImpl.java
new file mode 100644
index 0000000..d58fa5b
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareInoutServiceImpl.java
@@ -0,0 +1,135 @@
+package org.dromara.eims.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsSpareInoutBo;
+import org.dromara.eims.domain.vo.EimsSpareInoutVo;
+import org.dromara.eims.domain.EimsSpareInout;
+import org.dromara.eims.mapper.EimsSpareInoutMapper;
+import org.dromara.eims.service.IEimsSpareInoutService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 澶囦欢鍑哄叆搴揝ervice涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-03-26
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsSpareInoutServiceImpl implements IEimsSpareInoutService {
+
+    private final EimsSpareInoutMapper baseMapper;
+
+    /**
+     * 鏌ヨ澶囦欢鍑哄叆搴�
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢鍑哄叆搴�
+     */
+    @Override
+    public EimsSpareInoutVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ澶囦欢鍑哄叆搴撳垪琛�
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 澶囦欢鍑哄叆搴撳垎椤靛垪琛�
+     */
+    @Override
+    public TableDataInfo<EimsSpareInoutVo> queryPageList(EimsSpareInoutBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<EimsSpareInout> lqw = buildQueryWrapper(bo);
+        Page<EimsSpareInoutVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠跺嚭鍏ュ簱鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢鍑哄叆搴撳垪琛�
+     */
+    @Override
+    public List<EimsSpareInoutVo> queryList(EimsSpareInoutBo bo) {
+        LambdaQueryWrapper<EimsSpareInout> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsSpareInout> buildQueryWrapper(EimsSpareInoutBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsSpareInout> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getOrderCode()), EimsSpareInout::getOrderCode, bo.getOrderCode());
+        lqw.between(params.get("beginOrderTime") != null && params.get("endOrderTime") != null,
+            EimsSpareInout::getOrderTime ,params.get("beginOrderTime"), params.get("endOrderTime"));
+        lqw.eq(bo.getChargeUser() != null, EimsSpareInout::getChargeUser, bo.getChargeUser());
+        lqw.eq(StringUtils.isNotBlank(bo.getType()), EimsSpareInout::getType, bo.getType());
+        lqw.like(StringUtils.isNotBlank(bo.getPartnerName()), EimsSpareInout::getPartnerName, bo.getPartnerName());
+        lqw.eq(StringUtils.isNotBlank(bo.getAssociatedOrder()), EimsSpareInout::getAssociatedOrder, bo.getAssociatedOrder());
+        return lqw;
+    }
+
+    /**
+     * 鏂板澶囦欢鍑哄叆搴�
+     *
+     * @param bo 澶囦欢鍑哄叆搴�
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsSpareInoutBo bo) {
+        EimsSpareInout add = MapstructUtils.convert(bo, EimsSpareInout.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼澶囦欢鍑哄叆搴�
+     *
+     * @param bo 澶囦欢鍑哄叆搴�
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsSpareInoutBo bo) {
+        EimsSpareInout update = MapstructUtils.convert(bo, EimsSpareInout.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsSpareInout entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠跺嚭鍏ュ簱淇℃伅
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareServiceImpl.java
new file mode 100644
index 0000000..1c8619a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareServiceImpl.java
@@ -0,0 +1,135 @@
+package org.dromara.eims.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsSpareBo;
+import org.dromara.eims.domain.vo.EimsSpareVo;
+import org.dromara.eims.domain.EimsSpare;
+import org.dromara.eims.mapper.EimsSpareMapper;
+import org.dromara.eims.service.IEimsSpareService;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 澶囦欢鍙拌处Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsSpareServiceImpl implements IEimsSpareService {
+
+    private final EimsSpareMapper baseMapper;
+
+    /**
+     * 鏌ヨ澶囦欢鍙拌处
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢鍙拌处
+     */
+    @Override
+    public EimsSpareVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ澶囦欢鍙拌处鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 澶囦欢鍙拌处鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<EimsSpareVo> queryPageList(EimsSpareBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<EimsSpare> lqw = buildQueryWrapper(bo);
+        Page<EimsSpareVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠跺彴璐﹀垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢鍙拌处鍒楄〃
+     */
+    @Override
+    public List<EimsSpareVo> queryList(EimsSpareBo bo) {
+        LambdaQueryWrapper<EimsSpare> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsSpare> buildQueryWrapper(EimsSpareBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsSpare> lqw = Wrappers.lambdaQuery();
+        lqw.eq(bo.getType() != null, EimsSpare::getType, bo.getType());
+        lqw.like(StringUtils.isNotBlank(bo.getName()), EimsSpare::getName, bo.getName());
+        lqw.like(StringUtils.isNotBlank(bo.getCode()), EimsSpare::getCode, bo.getCode());
+        lqw.like(StringUtils.isNotBlank(bo.getModelNo()), EimsSpare::getModelNo, bo.getModelNo());
+        lqw.like(StringUtils.isNotBlank(bo.getMadeIn()), EimsSpare::getMadeIn, bo.getMadeIn());
+        lqw.like(StringUtils.isNotBlank(bo.getSupplier()), EimsSpare::getSupplier, bo.getSupplier());
+        lqw.eq(StringUtils.isNotBlank(bo.getUnit()), EimsSpare::getUnit, bo.getUnit());
+        return lqw;
+    }
+
+    /**
+     * 鏂板澶囦欢鍙拌处
+     *
+     * @param bo 澶囦欢鍙拌处
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsSpareBo bo) {
+        EimsSpare add = MapstructUtils.convert(bo, EimsSpare.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼澶囦欢鍙拌处
+     *
+     * @param bo 澶囦欢鍙拌处
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsSpareBo bo) {
+        EimsSpare update = MapstructUtils.convert(bo, EimsSpare.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsSpare entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠跺彴璐︿俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareTypeServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareTypeServiceImpl.java
new file mode 100644
index 0000000..870b9f4
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsSpareTypeServiceImpl.java
@@ -0,0 +1,188 @@
+package org.dromara.eims.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.service.SpareTypeService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.eims.domain.EimsEquType;
+import org.dromara.eims.domain.EimsSpareType;
+import org.dromara.eims.domain.bo.EimsSpareTypeBo;
+import org.dromara.eims.domain.vo.EimsEquTypeVo;
+import org.dromara.eims.domain.vo.EimsSpareTypeVo;
+import org.dromara.eims.mapper.EimsSpareTypeMapper;
+import org.dromara.eims.service.IEimsSpareTypeService;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 澶囦欢绫诲瀷Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-03-20
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsSpareTypeServiceImpl implements IEimsSpareTypeService, SpareTypeService {
+
+    private final EimsSpareTypeMapper baseMapper;
+
+    /**
+     * 鏌ヨ澶囦欢绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 澶囦欢绫诲瀷
+     */
+    @Override
+    public EimsSpareTypeVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫浠剁被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 澶囦欢绫诲瀷鍒楄〃
+     */
+    @Override
+    public List<EimsSpareTypeVo> queryList(EimsSpareTypeBo bo) {
+        LambdaQueryWrapper<EimsSpareType> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsSpareType> buildQueryWrapper(EimsSpareTypeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsSpareType> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getTypeName()), EimsSpareType::getTypeName, bo.getTypeName());
+        lqw.eq(StringUtils.isNotBlank(bo.getTypeCode()), EimsSpareType::getTypeCode, bo.getTypeCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getMenuType()), EimsSpareType::getMenuType, bo.getMenuType());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), EimsSpareType::getStatus, bo.getStatus());
+        return lqw;
+    }
+
+    /**
+     * 鏂板澶囦欢绫诲瀷
+     *
+     * @param bo 澶囦欢绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsSpareTypeBo bo) {
+        EimsSpareType add = MapstructUtils.convert(bo, EimsSpareType.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼澶囦欢绫诲瀷
+     *
+     * @param bo 澶囦欢绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsSpareTypeBo bo) {
+        EimsSpareType update = MapstructUtils.convert(bo, EimsSpareType.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsSpareType entity){
+        //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+    }
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ浠剁被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    @Override
+    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+        if(isValid){
+            //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+        }
+        return baseMapper.deleteByIds(ids) > 0;
+    }
+    @Override
+    public boolean hasChildBySpareTypeId(Long id) {
+        return baseMapper.exists(new LambdaQueryWrapper<EimsSpareType>().eq(EimsSpareType::getParentId, id));
+    }
+
+    @Override
+    public List<Tree<Long>> selectSpareTypeTreeList(EimsSpareTypeBo bo) {
+        // 鍙煡璇㈡湭绂佺敤绫诲瀷
+        bo.setStatus(UserConstants.DEPT_NORMAL);
+        LambdaQueryWrapper<EimsSpareType> lqw = buildQueryWrapper(bo);
+        List<EimsSpareTypeVo> typeVoList = baseMapper.selectVoList(lqw);
+
+        for (int i = 0; i < typeVoList.size(); i++) {
+            EimsSpareTypeVo typeVo = typeVoList.get(i);
+            if(typeVo.getParentId() == null){
+                typeVoList.get(i).setParentId(0L);
+            }
+        }
+        //鍔犳牴鐩綍
+        EimsSpareTypeVo root = new EimsSpareTypeVo();
+        root.setId(0L);
+        root.setMenuType("M");
+        root.setTypeName("鎵�鏈夊浠�");
+        root.setStatus("0");
+        root.setTypeCode("0");
+        root.setOrderNum(0L);
+        root.setIcon("#");
+        typeVoList.add(root);
+        typeVoList.sort((o1, o2) -> o1.getId().compareTo(o2.getId()));
+
+
+        return buildEquTypeTreeSelect(typeVoList);
+    }
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param typeVoList 绫诲瀷鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    public List<Tree<Long>> buildEquTypeTreeSelect(List<EimsSpareTypeVo> typeVoList) {
+        if (CollUtil.isEmpty(typeVoList)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeBuildUtils.build(typeVoList, (dept, tree) ->
+            tree.setId(dept.getId())
+                .setParentId(dept.getParentId())
+                .setName(dept.getTypeName())
+                .setWeight(dept.getOrderNum()));
+    }
+
+    @Override
+    public String selectSpareTypeNameByIds(String spareTypeIds) {
+        List<String> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(spareTypeIds, Convert::toLong)) {
+            EimsSpareTypeVo vo = SpringUtils.getAopProxy(this).queryById(id);
+            if (ObjectUtil.isNotNull(vo)) {
+                list.add(vo.getTypeName());
+            }
+        }
+        return String.join(StringUtils.SEPARATOR, list);
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFaultKnowMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFaultKnowMapper.xml
new file mode 100644
index 0000000..84fef09
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFaultKnowMapper.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.EimsFaultKnowMapper">
+    <resultMap type="org.dromara.eims.domain.vo.EimsFaultKnowVo" id="EimsFaultKnowVoResult">
+    </resultMap>
+    <select id="selectFaultKnowList" resultMap="EimsFaultKnowVoResult">
+        SELECT fk.*, eu.equ_name equName, eu.asset_no assetNo, et.type_name equTypeName
+        FROM eims_fault_know fk
+                 LEFT JOIN eims_equ eu ON fk.equ_id = eu.equ_id
+                 LEFT JOIN eims_equ_type et ON eu.equ_type_id = et.equ_type_id
+            ${ew.getCustomSqlSegment}
+    </select>
+</mapper>
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareInoutMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareInoutMapper.xml
new file mode 100644
index 0000000..3bf467d
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareInoutMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.EimsSpareInoutMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareMapper.xml
new file mode 100644
index 0000000..8384ab3
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.EimsSpareMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareTypeMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareTypeMapper.xml
new file mode 100644
index 0000000..e522aa4
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsSpareTypeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.eims.mapper.EimsSpareTypeMapper">
+
+</mapper>
diff --git a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
index 1866531..818dff6 100644
--- a/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
+++ b/eims/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java
@@ -195,7 +195,7 @@
         OssClient storage = OssFactory.instance();
         UploadResult uploadResult;
         try {
-            uploadResult = storage.uploadSuffix(file.getBytes(), suffix);
+            uploadResult = storage.uploadSuffix(file.getBytes(), suffix,originalfileName);
         } catch (IOException e) {
             throw new ServiceException(e.getMessage());
         }

--
Gitblit v1.9.3