From 2c3d6ae9d456ad2cf0b3047d6421ef6f36d216d0 Mon Sep 17 00:00:00 2001
From: 朱桂飞 <zhuguifei@zhuguifeideMacBook-Air.local>
Date: 星期一, 17 二月 2025 16:01:55 +0800
Subject: [PATCH] 新增工具治具模块

---
 eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue                                                                                     |    2 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureController.java                                                |  105 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureServiceImpl.java                                             |  196 +++
 eims-ui/apps/web-antd/src/views/eims/fixture-type/index.vue                                                                                    |  170 +++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureMapper.java                                                        |   15 
 eims-ui/apps/web-antd/src/views/eims/fixture-type/fixture-type-drawer.vue                                                                      |  132 ++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureTypeVo.java                                                     |   89 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureService.java                                                     |   68 +
 eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue                                                                          |  112 ++
 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/java/org/dromara/eims/domain/EimsFixtureType.java                                                          |   71 +
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/FixtureTypeService.java                                      |   11 
 eims-ui/packages/@core/base/shared/src/constants/dict-enum.ts                                                                                  |    1 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureTypeController.java                                            |  117 ++
 eims-ui/apps/web-antd/src/views/eims/equ/index.vue                                                                                             |    8 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureTypeMapper.java                                                    |   15 
 eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue                                                                                        |    2 
 eims-ui/apps/web-antd/src/views/eims/fixture/data.tsx                                                                                          |  245 ++++
 eims-ui/apps/web-antd/src/views/eims/fixture/index.vue                                                                                         |  285 +++++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureTypeServiceImpl.java                                         |  183 +++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureTypeBo.java                                                     |   76 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsEquTypeServiceImpl.java                                             |    2 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureVo.java                                                         |  150 ++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquTypeVo.java                                                         |    3 
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java                            |    4 
 eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFixtureMapper.xml                                                                |    7 
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureBo.java                                                         |  110 ++
 eims-ui/apps/web-antd/src/api/eims/fixture/index.ts                                                                                            |   92 +
 eims-ui/apps/web-antd/src/api/eims/fixture-type/index.ts                                                                                       |   69 +
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixture.java                                                              |  110 ++
 eims-ui/apps/web-antd/src/api/eims/fixture-type/model.d.ts                                                                                     |   67 +
 eims-ui/apps/web-antd/src/api/eims/fixture/model.d.ts                                                                                          |  172 +++
 eims-ui/apps/web-antd/src/views/eims/fixture/fixture-drawer.vue                                                                                |  212 +++
 eims-ui/apps/web-antd/src/views/eims/fixture-type/data.tsx                                                                                     |  196 +++
 eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureTypeService.java                                                 |   68 +
 eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/FixtureTypeNameTranslationImpl.java          |   29 
 eims-ui/apps/web-antd/src/views/eims/fixture/fixture-type-tree.vue                                                                             |  103 +
 37 files changed, 3,286 insertions(+), 12 deletions(-)

diff --git a/eims-ui/apps/web-antd/src/api/eims/fixture-type/index.ts b/eims-ui/apps/web-antd/src/api/eims/fixture-type/index.ts
new file mode 100644
index 0000000..8ede908
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fixture-type/index.ts
@@ -0,0 +1,69 @@
+import type { FixtureTypeTree, FixtureTypeVO } from './model';
+
+import type { ID, IDS } from '#/api/common';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  fixtureTypeExport = '/eims/fixtureType/export',
+  fixtureTypeList = '/eims/fixtureType/list',
+  fixtureTypeTree = '/eims/fixtureType/tree',
+  root = '/eims/fixtureType'
+}
+
+/**
+ * 鏌ヨ宸ュ叿绫诲瀷鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export function listFixtureType(params?: any) {
+  return requestClient.get<FixtureTypeVO[]>(Api.fixtureTypeList, { params });
+}
+
+/**
+ * 鑾峰彇宸ュ叿绫诲瀷鏍�
+ * @returns 宸ュ叿鏍戞暟缁�
+ */
+export function getFixtureTypeTree() {
+  return requestClient.get<FixtureTypeTree[]>(Api.fixtureTypeTree);
+}
+
+/**
+ * 鏌ヨ宸ュ叿绫诲瀷璇︾粏
+ * @param fixTypeId
+ */
+export function getFixtureType(fixTypeId: ID) {
+  return requestClient.get<FixtureTypeVO>(`${Api.root}/${fixTypeId}`);
+}
+
+/**
+ * 鏂板宸ュ叿绫诲瀷
+ * @param data
+ */
+export function addFixtureType(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+/**
+ * 淇敼宸ュ叿绫诲瀷
+ * @param data
+ */
+export function updateFixtureType(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎宸ュ叿绫诲瀷
+ * @param fixTypeId
+ */
+export function delFixtureType(fixTypeId: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${fixTypeId}`);
+}
+/**
+ * 瀵煎嚭
+ * @param
+ */
+export function fixtureTypeExport(data: any) {
+  return commonExport(Api.fixtureTypeExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/fixture-type/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/fixture-type/model.d.ts
new file mode 100644
index 0000000..f8c5da8
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fixture-type/model.d.ts
@@ -0,0 +1,67 @@
+export interface FixtureTypeVO {
+  /**
+   * 绫诲瀷id
+   */
+  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: FixtureTypeVO[];
+}
+
+/**
+ * @description: 璁惧绫诲瀷鏍�
+ */
+export interface FixtureTypeTree {
+  id: number;
+  /**
+   * antd缁勪欢蹇呴』瑕佽繖涓睘鎬� 瀹為檯鏄病鏈夎繖涓睘鎬х殑
+   */
+  key: string;
+  parentId: number;
+  label: string;
+  weight: number;
+  children?: FixtureTypeTree[];
+}
+
diff --git a/eims-ui/apps/web-antd/src/api/eims/fixture/index.ts b/eims-ui/apps/web-antd/src/api/eims/fixture/index.ts
new file mode 100644
index 0000000..69a8abd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fixture/index.ts
@@ -0,0 +1,92 @@
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+import type { FixtureImportParam, FixtureVO } from '#/api/eims/fixture/model';
+
+import { commonExport, ContentTypeEnum } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  fixtureExport = '/eims/fixture/export',
+  fixtureImport = '/eims/fixture/importData',
+  fixtureImportTemplate = '/eims/fixture/importTemplate',
+  fixtureList = '/eims/fixture/list',
+  root = '/eims/fixture'
+}
+
+/**
+ * 鏌ヨ銆愬伐鍏峰彴璐︺�戝垪琛�
+ * @param query
+ * @returns {*}
+ */
+
+export function listFixture(params?: PageQuery) {
+  return requestClient.get<PageResult<FixtureVO>>(Api.fixtureList, { params });
+}
+
+/**
+ * 鏌ヨ銆愬伐鍏峰彴璐︺�戣缁�
+ * @param fixId
+ */
+export function getFixture(fixId: any) {
+  return requestClient.get<FixtureVO>(`${Api.root}/${fixId}`);
+}
+
+/**
+ * 鏂板銆愬伐鍏峰彴璐︺��
+ * @param data
+ */
+export function addFixture(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼銆愬伐鍏峰彴璐︺��
+ * @param data
+ */
+export function updateFixture(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎銆愬伐鍏峰彴璐︺��
+ * @param fixIds
+ */
+export function delFixture(fixIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${fixIds}`);
+}
+
+/**
+ * 瀵煎嚭銆愬伐鍏峰彴璐︺��
+ * @param data
+ */
+export function fixtureExport(data: any) {
+  return commonExport(Api.fixtureExport, data);
+}
+
+/**
+ * 浠巈xcel瀵煎叆璁惧
+ * @param data
+ * @returns void
+ */
+export function fixtureImportData(data: FixtureImportParam) {
+  return requestClient.post<{ code: number; msg: string }>(Api.fixtureImport, data, {
+    headers: {
+      'Content-Type': ContentTypeEnum.FORM_DATA
+    },
+    isTransformResponse: false
+  });
+}
+
+/**
+ * 涓嬭浇瀵煎叆妯℃澘
+ * @returns blob
+ */
+export function downloadImportTemplate() {
+  return requestClient.post<Blob>(
+    Api.fixtureImportTemplate,
+    {},
+    {
+      isTransformResponse: false,
+      responseType: 'blob'
+    }
+  );
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/fixture/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/fixture/model.d.ts
new file mode 100644
index 0000000..5378041
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/fixture/model.d.ts
@@ -0,0 +1,172 @@
+export interface FixtureVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 娌诲叿缂栫爜
+   */
+  fixtureCode: string;
+
+  /**
+   * 娌诲叿鍚嶇О
+   */
+  fixtureName: string;
+
+  /**
+   * 娌诲叿锛堝伐鍏凤級绫诲瀷
+   */
+  fixtureType: number;
+
+  /**
+   * 娌诲叿鎻忚堪
+   */
+  fixtureDesc: string;
+
+  /**
+   * 鍊熺敤閮ㄩ棬
+   */
+  borrowDept: number | string;
+  /**
+   * 鍊熺敤閮ㄩ棬
+   */
+  borrowDeptName: string;
+
+  /**
+   * 鍊熺敤浜�
+   */
+  borrowUser: number | string;
+  /**
+   * 鍊熺敤浜�
+   */
+  borrowUserName: string;
+
+  /**
+   * 鐘舵�侊紙瀛楀吀锛�
+   */
+  status: string;
+
+  /**
+   * 璧勪骇缂栧彿
+   */
+  assetNo: string;
+
+  /**
+   * 鍨嬪彿
+   */
+  modelNo: string;
+
+  /**
+   * 瑙勬牸
+   */
+  specNo: string;
+
+  /**
+   * 鍒堕�犲晢
+   */
+  madeIn: string;
+
+  /**
+   * 閲囪喘鏃ユ湡
+   */
+  purchaseDate: string;
+
+  /**
+   * 浣跨敤鏃ユ湡
+   */
+  deployDate: string;
+
+  /**
+   * 浣跨敤骞撮檺
+   */
+  serviceLife: number;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
+
+export interface FixtureForm extends BaseEntity {
+  /**
+   *
+   */
+  id?: number | string;
+
+  /**
+   * 娌诲叿缂栫爜
+   */
+  fixtureCode?: string;
+
+  /**
+   * 娌诲叿鍚嶇О
+   */
+  fixtureName?: string;
+
+  /**
+   * 娌诲叿锛堝伐鍏凤級绫诲瀷
+   */
+  fixtureType?: number;
+
+  /**
+   * 娌诲叿鎻忚堪
+   */
+  fixtureDesc?: string;
+
+  /**
+   * 鐘舵�侊紙瀛楀吀锛�
+   */
+  status?: string;
+
+  /**
+   * 璧勪骇缂栧彿
+   */
+  assetNo?: string;
+
+  /**
+   * 鍨嬪彿
+   */
+  modelNo?: string;
+
+  /**
+   * 瑙勬牸
+   */
+  specNo?: string;
+
+  /**
+   * 鍒堕�犲晢
+   */
+  madeIn?: string;
+
+  /**
+   * 閲囪喘鏃ユ湡
+   */
+  purchaseDate?: string;
+
+  /**
+   * 浣跨敤鏃ユ湡
+   */
+  deployDate?: string;
+
+  /**
+   * 浣跨敤骞撮檺
+   */
+  serviceLife?: number;
+
+  /**
+   * 澶囨敞
+   */
+  remark?: string;
+}
+
+/**
+ * @description: 璁惧瀵煎叆
+ * @param updateSupport 鏄惁瑕嗙洊鏁版嵁
+ * @param file excel鏂囦欢
+ */
+export interface FixtureImportParam {
+  updateSupport: boolean;
+  file: Blob | File;
+}
+
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue b/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue
index cafb9e6..99f1b4d 100644
--- a/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/equ-type/index.vue
@@ -130,7 +130,7 @@
 
 <template>
   <Page :auto-content-height="true">
-    <BasicTable table-title="鑿滃崟鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
+    <BasicTable table-title="璁惧绫诲瀷鍒楄〃" table-title-help="鍙屽嚮灞曞紑/鏀惰捣瀛愯彍鍗�">
       <template #toolbar-tools>
         <Space>
           <a-button @click="setExpandOrCollapse(false)">
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue b/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue
index 0dd28c0..8183ed3 100644
--- a/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/equ-type-tree.vue
@@ -111,7 +111,7 @@
           <div v-else class="mt-5">
             <Empty
               :image="Empty.PRESENTED_IMAGE_SIMPLE"
-              description="鏃犻儴闂ㄦ暟鎹�"
+              description="鏃犺澶囩被鍨嬫暟鎹�"
             />
           </div>
         </div>
diff --git a/eims-ui/apps/web-antd/src/views/eims/equ/index.vue b/eims-ui/apps/web-antd/src/views/eims/equ/index.vue
index 1dc33e5..febbba8 100644
--- a/eims-ui/apps/web-antd/src/views/eims/equ/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/equ/index.vue
@@ -149,10 +149,6 @@
   });
 }
 
-function getImportStatus(row: any) {
-  const importStatus = row.importStatus === null || row.importStatus;
-  return importStatus ? '鏈鍏�' : '宸插鍏�';
-}
 
 const router = useRouter();
 function handleDetail(record: Recordable<any>) {
@@ -206,10 +202,6 @@
               </ghost-button>
             </Popconfirm>
           </Space>
-        </template>
-
-        <template #importStatus="{ row }">
-          <span>{{ getImportStatus(row) }}</span>
         </template>
       </BasicTable>
     </div>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture-type/data.tsx b/eims-ui/apps/web-antd/src/views/eims/fixture-type/data.tsx
new file mode 100644
index 0000000..8da8df7
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture-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 fixtureTypeOptions = [
+  { 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: fixtureTypeOptions,
+      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/fixture-type/fixture-type-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/fixture-type/fixture-type-drawer.vue
new file mode 100644
index 0000000..8cb4754
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture-type/fixture-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 { addFixtureType, getFixtureType, listFixtureType, updateFixtureType } from '#/api/eims/fixture-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 setupFixtureTypeSelect() {
+  // menu
+  const menuArray = await listFixtureType({ 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 setupFixtureTypeSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (update) {
+        const record = await getFixtureType(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 ? updateFixtureType(data) : addFixtureType(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/fixture-type/index.vue b/eims-ui/apps/web-antd/src/views/eims/fixture-type/index.vue
new file mode 100644
index 0000000..7f34e0c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture-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 { $t } from '@vben/locales';
+import { eachTree, getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps } from '#/adapter/vxe-table';
+import { delFixtureType, fixtureTypeExport, listFixtureType } from '#/api/eims/fixture-type';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import fixtureTypeDrawer from './fixture-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 listFixtureType({
+          ...formValues
+        });
+        return { rows: resp };
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  /**
+   * 寮�鍚櫄鎷熸粴鍔�
+   * 鏁版嵁閲忓皬鍙互閫夋嫨鍏抽棴
+   * 濡傛灉閬囧埌鏍峰紡闂(绌虹櫧銆侀敊浣� 婊氬姩绛�)鍙互閫夋嫨鍏抽棴铏氭嫙婊氬姩
+   */
+  scrollY: {
+    enabled: true,
+    gt: 0
+  },
+  treeConfig: {
+    parentField: 'parentId',
+    rowField: 'id',
+    // 鑷姩杞崲涓簍ree 鐢眝xe澶勭悊 鏃犻渶鎵嬪姩杞崲
+    transform: true
+  },
+  id: 'fixture-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 [FixtureTypeDrawer, drawerApi] = useVbenDrawer({
+  connectedComponent: fixtureTypeDrawer
+});
+
+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 delFixtureType(row.id);
+  await tableApi.query();
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(fixtureTypeExport, '宸ュ叿绫诲瀷', 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:fixtureType:export']" @click="handleDownloadExcel">
+            {{ $t('pages.common.export') }}
+          </a-button>
+          <a-button type="primary" v-access:code="['eims:fixtureType:add']" @click="handleAdd">
+            {{ $t('pages.common.add') }}
+          </a-button>
+        </Space>
+      </template>
+      <template #action="{ row }">
+        <Space>
+          <ghost-button v-access:code="['eims:fixtureType:edit']" @click="handleEdit(row)">
+            {{ $t('pages.common.edit') }}
+          </ghost-button>
+          <!-- '鎸夐挳绫诲瀷'鏃犳硶鍐嶆坊鍔犲瓙鑿滃崟 -->
+          <ghost-button v-if="row.menuType !== 'F'" class="btn-success" v-access:code="['eims:fixtureType: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:fixtureType:remove']" @click.stop="">
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+    <FixtureTypeDrawer @reload="tableApi.query()" />
+  </Page>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture/data.tsx b/eims-ui/apps/web-antd/src/views/eims/fixture/data.tsx
new file mode 100644
index 0000000..8b58bfd
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/data.tsx
@@ -0,0 +1,245 @@
+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';
+import { renderDict } from '#/utils/render';
+
+export const querySchema: FormSchemaGetter = () => [
+  {
+    component: 'Input',
+    fieldName: 'fixtureName',
+    label: '宸ュ叿鍚嶇О'
+  },
+  {
+    component: 'Input',
+    fieldName: 'fixtureCode',
+    label: '宸ュ叿缂栫爜'
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      options: getDictOptions(DictEnum.EIMS_FIXTURE_STATUS)
+    },
+    fieldName: 'status',
+    label: '宸ュ叿鐘舵��'
+  },
+  {
+    component: 'Input',
+    fieldName: 'assetNo',
+    label: '璧勪骇缂栧彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'modelNo',
+    label: '宸ュ叿鍨嬪彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'specNo',
+    label: '宸ュ叿瑙勬牸'
+  },
+  {
+    component: 'TreeSelect',
+    // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
+    defaultValue: undefined,
+    fieldName: 'borrowDept',
+    label: '鍊熺敤閮ㄩ棬',
+    // rules: 'selectRequired',
+  },
+  {
+    component: 'Select',
+    componentProps: {
+      showSearch: true,
+      allowClear: true,
+      getPopupContainer
+    },
+    fieldName: 'borrowUser',
+    label: '鍊熺敤浜�'
+  },
+  {
+    component: 'Input',
+    fieldName: 'madeIn',
+    label: '鍒堕�犲晢'
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'purchaseDate',
+    label: '閲囪喘鏃ユ湡'
+  },
+  {
+    component: 'RangePicker',
+    fieldName: 'deployDate',
+    label: '浣跨敤鏃ユ湡'
+  }
+];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '宸ュ叿(娌诲叿)鍚嶇О',
+    field: 'fixtureName',
+    minWidth: 140,
+    fixed: 'left'
+  },
+
+  {
+    title: '鐘舵��',
+    field: 'status',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (row.status === null || row.status === '') {
+          return '';
+        }
+        return renderDict(row.status, DictEnum.EIMS_FIXTURE_STATUS);
+      }
+    },
+    minWidth: 80,
+    fixed: 'left'
+  },
+  {
+    title: '绫诲瀷',
+    field: 'fixtureTypeName',
+    minWidth: 100
+  },
+  {
+    title: '璧勪骇缂栧彿',
+    field: 'assetNo',
+    sortable: true,
+    minWidth: 140
+  },
+  {
+    title: '宸ュ叿缂栫爜',
+    field: 'fixtureCode',
+    sortable: true,
+    minWidth: 100
+  },
+  {
+    title: '鍨嬪彿',
+    field: 'modelNo',
+    minWidth: 100
+  },
+  {
+    title: '瑙勬牸',
+    field: 'specNo',
+    minWidth: 100
+  },
+  {
+    title: '鍒堕�犲晢',
+    field: 'madeIn',
+    minWidth: 140
+  },
+  {
+    title: '閲囪喘鏃ユ湡',
+    field: 'purchaseDate',
+    minWidth: 140
+  },
+  {
+    title: '浣跨敤鏃ユ湡',
+    field: 'deployDate',
+    minWidth: 140
+  },
+  {
+    title: '浣跨敤骞撮檺',
+    field: 'serviceLife',
+    minWidth: 100
+  },
+  {
+    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: 'fixtureType',
+    label: '宸ュ叿绫诲瀷',
+    rules: 'selectRequired'
+  },
+  {
+    component: 'Input',
+    fieldName: 'fixtureName',
+    label: '宸ュ叿鍚嶇О',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'fixtureCode',
+    label: '宸ュ叿缂栫爜',
+    rules: 'required'
+  },
+  {
+    component: 'Input',
+    fieldName: 'assetNo',
+    label: '璧勪骇缂栧彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'modelNo',
+    label: '鍨嬪彿'
+  },
+  {
+    component: 'Input',
+    fieldName: 'specNo',
+    label: '瑙勬牸'
+  },
+  {
+    component: 'Input',
+    fieldName: 'madeIn',
+    label: '鍒堕�犲晢'
+  },
+  {
+    component: 'RadioGroup',
+    componentProps: {
+      buttonStyle: 'solid',
+      options: getDictOptions(DictEnum.EIMS_FIXTURE_STATUS),
+      optionType: 'button'
+    },
+    defaultValue: '0',
+    fieldName: 'status',
+    label: '鐘舵��'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'purchaseDate',
+    label: '閲囪喘鏃ユ湡'
+  },
+  {
+    component: 'DatePicker',
+    componentProps: {
+      format: 'YYYY-MM-DD',
+      showTime: false,
+      valueFormat: 'YYYY-MM-DD',
+      getPopupContainer
+    },
+    fieldName: 'deployDate',
+    label: '浣跨敤鏃ユ湡'
+  },
+  {
+    component: 'Input',
+    fieldName: 'serviceLife',
+    label: '浣跨敤骞撮檺'
+  }
+];
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-drawer.vue
new file mode 100644
index 0000000..f91f8d6
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-drawer.vue
@@ -0,0 +1,212 @@
+<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 { addFixture, getFixture, updateFixture } from '#/api/eims/fixture';
+import { getFixtureType, listFixtureType } from '#/api/eims/fixture-type';
+import { getDeptTree, userList } from '#/api/system/user';
+
+import { drawerSchema } from './data';
+
+const emit = defineEmits<{ reload: [] }>();
+const typeDisabled = ref(false);
+
+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,
+  closeOnPressEscape: true,
+  placement: 'left',
+  onConfirm: handleConfirm,
+  async onOpenChange(isOpen) {
+    if (!isOpen) {
+      return null;
+    }
+    drawerApi.drawerLoading(true);
+    const { id } = drawerApi.getData() as { id?: number | string };
+    const { typeDisable } = drawerApi.getData() as { typeDisable?: boolean };
+    typeDisabled.value = !!typeDisable;
+    isUpdate.value = !!id;
+    // 鍒濆鍖�
+    await setupDeptSelect();
+    // 鏇存柊 && 璧嬪��
+    if (isUpdate.value && id) {
+      const record = await getFixture(id);
+      await formApi.setValues(record);
+      if (isUpdate.value && record.borrowDept) {
+        await setupUserOptions(record.borrowDept);
+      }
+    }
+
+    // 鍔犺浇宸ュ叿绫诲瀷鏍戦�夋嫨
+    await setupFixtureTypeSelect();
+    if (id) {
+      await formApi.setFieldValue('parentId', id);
+      if (isUpdate.value && id) {
+        const record = await getFixtureType(id);
+        await formApi.setValues(record);
+      }
+    }
+    drawerApi.drawerLoading(false);
+  }
+});
+
+async function setupFixtureTypeSelect() {
+  // status-0 鍙煡璇㈡湭鍋滅敤宸ュ叿
+  const fixArray = await listFixtureType({ status: 0 });
+  // support i18n
+  fixArray.forEach((item) => {
+    item.typeName = $t(item.typeName);
+  });
+  const fixTree = listToTree(fixArray, { id: 'id', pid: 'parentId' });
+  const fullTree = [
+    {
+      id: 0,
+      typeName: $t('menu.root'),
+      children: fixTree
+    }
+  ];
+  addFullName(fullTree, 'typeName', ' / ');
+  formApi.updateSchema([
+    {
+      componentProps: {
+        fieldNames: {
+          label: 'typeName',
+          value: 'id'
+        },
+        getPopupContainer,
+        // 璁剧疆寮圭獥婊氬姩楂樺害 榛樿256
+        listHeight: 300,
+        showSearch: true,
+        treeData: fullTree,
+        disabled: typeDisabled.value,
+        treeDefaultExpandAll: false,
+        // 榛樿灞曞紑鐨勬爲鑺傜偣
+        treeDefaultExpandedKeys: [0],
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'typeName',
+        treeNodeLabelProp: 'fullName'
+      },
+      fieldName: 'fixtureType'
+    }
+  ]);
+}
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+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: 'borrowUser'
+    }
+  ]);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+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.respPerson = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'borrowDept'
+    }
+  ]);
+}
+
+async function handleConfirm() {
+  try {
+    drawerApi.drawerLoading(true);
+    const { valid } = await formApi.validate();
+    if (!valid) {
+      return;
+    }
+    const data = cloneDeep(await formApi.getValues());
+    await (isUpdate.value ? updateFixture(data) : addFixture(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/fixture/fixture-import-modal.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue
new file mode 100644
index 0000000..e0f1e9e
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-import-modal.vue
@@ -0,0 +1,112 @@
+<script setup lang="ts">
+import type { UploadFile } from 'ant-design-vue/es/upload/interface';
+
+import { h, ref, unref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { ExcelIcon, InBoxIcon } from '@vben/icons';
+
+import { Modal, Switch, Upload } from 'ant-design-vue';
+
+import { downloadImportTemplate, equImportData } from '#/api/eims/equ';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+const emit = defineEmits<{ reload: [] }>();
+
+const UploadDragger = Upload.Dragger;
+
+const [BasicModal, modalApi] = useVbenModal({
+  onCancel: handleCancel,
+  onConfirm: handleSubmit,
+});
+
+const fileList = ref<UploadFile[]>([]);
+const checked = ref(false);
+
+async function handleSubmit() {
+  try {
+    modalApi.modalLoading(true);
+    if (fileList.value.length !== 1) {
+      handleCancel();
+      return;
+    }
+    const data = {
+      file: fileList.value[0]!.originFileObj as Blob,
+      updateSupport: unref(checked),
+    };
+    const { code, msg } = await equImportData(data);
+    let modal = Modal.success;
+    if (code === 200) {
+      emit('reload');
+    } else {
+      emit('reload');
+      modal = Modal.error;
+    }
+    handleCancel();
+    modal({
+      content: h('div', {
+        class: 'max-h-[260px] overflow-y-auto',
+        innerHTML: msg, // 鍚庡彴宸茬粡澶勭悊xss闂
+      }),
+      title: '鎻愮ず',
+    });
+  } catch (error) {
+    console.warn(error);
+    modalApi.close();
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+function handleCancel() {
+  modalApi.close();
+  fileList.value = [];
+  checked.value = false;
+}
+</script>
+
+<template>
+  <BasicModal
+    :close-on-click-modal="false"
+    :fullscreen-button="false"
+    title="璁惧瀵煎叆"
+  >
+    <!-- z-index涓嶈缃細閬尅妯℃澘涓嬭浇loading -->
+    <!-- 鎵嬪姩澶勭悊 鑰屼笉鏄斁鍏ユ枃浠跺氨涓婁紶 -->
+    <UploadDragger
+      v-model:file-list="fileList"
+      :before-upload="() => false"
+      :max-count="1"
+      :show-upload-list="true"
+      accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel"
+    >
+      <p class="ant-upload-drag-icon flex items-center justify-center">
+        <InBoxIcon class="text-primary size-[48px]" />
+      </p>
+      <p class="ant-upload-text">鐐瑰嚮鎴栬�呮嫋鎷藉埌姝ゅ涓婁紶鏂囦欢</p>
+    </UploadDragger>
+    <div class="mt-2 flex flex-col gap-2">
+      <div class="flex items-center gap-2">
+        <span>鍏佽瀵煎叆xlsx, xls鏂囦欢</span>
+        <a-button
+          type="link"
+          @click="commonDownloadExcel(downloadImportTemplate, '璁惧瀵煎叆妯℃澘')"
+        >
+          <div class="flex items-center gap-[4px]">
+            <ExcelIcon />
+            <span>涓嬭浇妯℃澘</span>
+          </div>
+        </a-button>
+      </div>
+      <div class="flex items-center gap-2">
+        <span class="text-red-500">鈿狅笍鐗瑰埆娉ㄦ剰鈿狅笍锛氳涓嬭浇妯$増淇濇寔瀵煎叆鏂囦欢琛ㄥご鍜屾ā鐗堜竴鑷村悗瀵煎叆</span>
+      </div>
+      <div class="flex items-center gap-2">
+        <span :class="{ 'text-red-500': checked }">
+          鏄惁鏇存柊/瑕嗙洊宸插瓨鍦ㄧ殑鐢ㄦ埛鏁版嵁
+        </span>
+        <Switch v-model:checked="checked" />
+      </div>
+    </div>
+  </BasicModal>
+</template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-type-tree.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-type-tree.vue
new file mode 100644
index 0000000..f3856b1
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/fixture-type-tree.vue
@@ -0,0 +1,103 @@
+<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 { getFixtureTypeTree } from '#/api/eims/fixture-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 DeptTreeArray = DeptTree[];
+const deptTreeArray = ref<DeptTreeArray>([]);
+/** 楠ㄦ灦灞忓姞杞� */
+const showTreeSkeleton = ref<boolean>(true);
+
+async function loadTree() {
+  showTreeSkeleton.value = true;
+  searchValue.value = '';
+  selectTypeId.value = [];
+
+  const ret = await getFixtureTypeTree();
+
+  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="selectTypeId"
+            :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/fixture/index.vue b/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue
new file mode 100644
index 0000000..76e3dde
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/fixture/index.vue
@@ -0,0 +1,285 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { onMounted, ref } from 'vue';
+import { useRouter } from 'vue-router';
+
+import { Page, useVbenDrawer, useVbenModal, 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 { delFixture, fixtureExport, listFixture } from '#/api/eims/fixture';
+import { getDeptTree, userList } from '#/api/system/user';
+import { commonDownloadExcel } from '#/utils/file/download';
+
+import { columns, querySchema } from './data';
+import fixtureDrawer from './fixture-drawer.vue';
+import fixtureImportModal from './fixture-import-modal.vue';
+import FixtureTypeTree from './fixture-type-tree.vue';
+
+// 宸﹁竟宸ュ叿绫诲瀷
+const selectTypeId = ref<string[]>([]);
+
+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);
+  },
+  // 鏃ユ湡閫夋嫨鏍煎紡鍖�
+  fieldMappingTime: [
+    ['purchaseDate', ['params[beginPurchaseDate]', 'params[endPurchaseDate]'], ['YYYY-MM-DD', 'YYYY-MM-DD']],
+    ['deployDate', ['params[beginDeployDate]', 'params[endDeployDate]'], ['YYYY-MM-DD', 'YYYY-MM-DD']]
+  ]
+};
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns,
+  height: 'auto',
+  keepSource: true,
+  pagerConfig: {},
+  proxyConfig: {
+    ajax: {
+      query: async ({ page }, formValues = {}) => {
+        // 閮ㄩ棬鏍戦�夋嫨澶勭悊
+        if (selectTypeId.value.length === 1) {
+          formValues.fixtureType = selectTypeId.value[0];
+        } else {
+          Reflect.deleteProperty(formValues, 'fixtureType');
+        }
+        return await listFixture({
+          pageNum: page.currentPage,
+          pageSize: page.pageSize,
+          ...formValues
+        });
+      }
+    }
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'fixtureId'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  id: 'eims-fixture-index'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  formOptions,
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+const [FixtureDrawer, fixtureDrawerApi] = useVbenDrawer({
+  connectedComponent: fixtureDrawer
+});
+
+/**
+ * 瀵煎叆
+ */
+const [FixtureImportModal, fixtureImportModalApi] = useVbenModal({
+  connectedComponent: fixtureImportModal
+});
+
+function handleImport() {
+  fixtureImportModalApi.open();
+}
+
+function handleAdd() {
+  fixtureDrawerApi.setData({});
+  fixtureDrawerApi.open();
+}
+
+async function handleEdit(record: Recordable<any>) {
+  fixtureDrawerApi.setData({ id: record.id });
+  fixtureDrawerApi.open();
+}
+
+async function handleDelete(row: Recordable<any>) {
+  await delFixture(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 delFixture(ids);
+      await tableApi.query();
+    }
+  });
+}
+
+function handleDownloadExcel() {
+  commonDownloadExcel(fixtureExport, '宸ュ叿鍙拌处', tableApi.formApi.form.values, {
+    fieldMappingTime: formOptions.fieldMappingTime
+  });
+}
+
+const router = useRouter();
+
+function handleDetail(record: Recordable<any>) {
+  router.push(`/fixture/detail/${record.id}`);
+}
+
+/**
+ * 鍒濆鍖栭儴闂ㄩ�夋嫨
+ */
+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.inventoryUser = undefined;
+        },
+        placeholder: '璇烽�夋嫨',
+        showSearch: true,
+        treeData: deptTree,
+        treeDefaultExpandAll: true,
+        treeLine: { showLeafIcon: false },
+        // 绛涢�夌殑瀛楁
+        treeNodeFilterProp: 'label',
+        // 閫変腑鍚庢樉绀哄湪杈撳叆妗嗙殑鍊�
+        treeNodeLabelProp: 'fullName'
+      }),
+      fieldName: 'borrowDept'
+    }
+  ]);
+}
+
+/**
+ * 鐢ㄦ埛鐨勫姞杞�
+ */
+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: 'borrowUser'
+    }
+  ]);
+}
+
+onMounted(async () => {
+  await setupDeptSelect();
+});
+</script>
+
+<template>
+  <Page :auto-content-height="true">
+    <div class="flex h-full gap-[8px]">
+      <FixtureTypeTree 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:fixture:export']" @click="handleDownloadExcel">
+              {{ $t('pages.common.export') }}
+            </a-button>
+            <a-button v-access:code="['eims:fixture:import']" @click="handleImport">
+              {{ $t('pages.common.import') }}
+            </a-button>
+            <a-button
+              :disabled="!vxeCheckboxChecked(tableApi)"
+              danger
+              type="primary"
+              v-access:code="['eims:fixture:remove']"
+              @click="handleMultiDelete"
+            >
+              {{ $t('pages.common.delete') }}
+            </a-button>
+            <a-button type="primary" v-access:code="['eims:fixture:add']" @click="handleAdd">
+              {{ $t('pages.common.add') }}
+            </a-button>
+          </Space>
+        </template>
+
+        <template #equName="{ row }">
+          <Space>
+            <a-button type="link" @click="handleDetail(row)"> {{ row.equName }}</a-button>
+          </Space>
+        </template>
+
+        <template #action="{ row }">
+          <Space>
+            <ghost-button v-access:code="['eims:fixture:edit']" @click.stop="handleEdit(row)">
+              {{ $t('pages.common.edit') }}
+            </ghost-button>
+            <ghost-button v-if="row.menuType !== 'F'" class="btn-success" v-access:code="['eims:fixture:list']" @click="handleDetail(row)">
+              {{ $t('pages.common.info') }}
+            </ghost-button>
+            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+              <ghost-button danger v-access:code="['eims:fixture:remove']" @click.stop="">
+                {{ $t('pages.common.delete') }}
+              </ghost-button>
+            </Popconfirm>
+          </Space>
+        </template>
+      </BasicTable>
+    </div>
+    <FixtureDrawer @reload="tableApi.query()" />
+    <FixtureImportModal @reload="tableApi.query()" />
+  </Page>
+</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 2ceef3e..f6546a1 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,5 +1,6 @@
 export enum DictEnum {
   EIMS_EQU_UNIT = 'eims_equ_unit', // 璁惧鐩樼偣鐘舵��
+  EIMS_FIXTURE_STATUS = 'eims_fixture_status', // 璁惧鐩樼偣鐘舵��
   EIMS_INVENTORY_DETAIL_STATU = 'inventory_detail_statu', // 璁惧鐩樼偣鐘舵��
   EIMS_INVENTORY_STATU = 'inventory_statu', // 璁惧鐩樼偣鐘舵��
   EQU_IMPORT_STATU = 'equ_import_status', // 璁惧瀵煎叆鐘舵��
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/FixtureTypeService.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/FixtureTypeService.java
new file mode 100644
index 0000000..458c5b7
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/FixtureTypeService.java
@@ -0,0 +1,11 @@
+package org.dromara.common.core.service;
+
+public interface FixtureTypeService {
+    /**
+     * 閫氳繃宸ュ叿绫诲瀷ID鏌ヨ宸ュ叿鍚嶇О
+     *
+     * @param fixIds 宸ュ叿ID涓查�楀彿鍒嗛殧
+     * @return 宸ュ叿绫诲瀷鍚嶇О涓查�楀彿鍒嗛殧
+     */
+    String selectFixtureTypeNameByIds(String fixIds);
+}
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 7a762a9..60065b7 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
@@ -40,5 +40,9 @@
      * 璁惧鍚嶇Оid杞悕绉�
      */
     String EQU_ID_TO_NAME = "equ_id_to_name";
+    /**
+     * 宸ュ叿绫诲瀷(娌诲叿)id杞悕绉�
+     */
+    String FIXTURE_TYPE_ID_TO_NAME = "fixture_type_id_to_name";
 
 }
diff --git a/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/FixtureTypeNameTranslationImpl.java b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/FixtureTypeNameTranslationImpl.java
new file mode 100644
index 0000000..f34fc75
--- /dev/null
+++ b/eims/ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/FixtureTypeNameTranslationImpl.java
@@ -0,0 +1,29 @@
+package org.dromara.common.translation.core.impl;
+
+import lombok.AllArgsConstructor;
+import org.dromara.common.core.service.FixtureTypeService;
+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.FIXTURE_TYPE_ID_TO_NAME)
+public class FixtureTypeNameTranslationImpl implements TranslationInterface<String> {
+
+    private final FixtureTypeService fixtureTypeService;
+
+    @Override
+    public String translation(Object key, String other) {
+        if (key instanceof String ids) {
+            return fixtureTypeService.selectFixtureTypeNameByIds(ids);
+        } else if (key instanceof Long id) {
+            return fixtureTypeService.selectFixtureTypeNameByIds(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 2db45d8..ec49dd6 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
@@ -6,3 +6,4 @@
 org.dromara.common.translation.core.impl.NicknameTranslationImpl
 org.dromara.common.translation.core.impl.EquTypeNameTranslationImpl
 org.dromara.common.translation.core.impl.EquNameTranslationImpl
+org.dromara.common.translation.core.impl.FixtureTypeNameTranslationImpl
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureController.java
new file mode 100644
index 0000000..f7cc822
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureController.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.EimsFixtureVo;
+import org.dromara.eims.domain.bo.EimsFixtureBo;
+import org.dromara.eims.service.IEimsFixtureService;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+
+/**
+ * 宸ュ叿(娌诲叿)鍙拌处
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/fixture")
+public class EimsFixtureController extends BaseController {
+
+    private final IEimsFixtureService eimsFixtureService;
+
+    /**
+     * 鏌ヨ宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     */
+    @SaCheckPermission("eims:fixture:list")
+    @GetMapping("/list")
+    public TableDataInfo<EimsFixtureVo> list(EimsFixtureBo bo, PageQuery pageQuery) {
+        return eimsFixtureService.queryPageList(bo, pageQuery);
+    }
+
+    /**
+     * 瀵煎嚭宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     */
+    @SaCheckPermission("eims:fixture:export")
+    @Log(title = "宸ュ叿(娌诲叿)鍙拌处", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(EimsFixtureBo bo, HttpServletResponse response) {
+        List<EimsFixtureVo> list = eimsFixtureService.queryList(bo);
+        ExcelUtil.exportExcel(list, "宸ュ叿(娌诲叿)鍙拌处", EimsFixtureVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇宸ュ叿(娌诲叿)鍙拌处璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:fixture:query")
+    @GetMapping("/{id}")
+    public R<EimsFixtureVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsFixtureService.queryById(id));
+    }
+
+    /**
+     * 鏂板宸ュ叿(娌诲叿)鍙拌处
+     */
+    @SaCheckPermission("eims:fixture:add")
+    @Log(title = "宸ュ叿(娌诲叿)鍙拌处", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsFixtureBo bo) {
+        return toAjax(eimsFixtureService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼宸ュ叿(娌诲叿)鍙拌处
+     */
+    @SaCheckPermission("eims:fixture:edit")
+    @Log(title = "宸ュ叿(娌诲叿)鍙拌处", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsFixtureBo bo) {
+        return toAjax(eimsFixtureService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:fixture:remove")
+    @Log(title = "宸ュ叿(娌诲叿)鍙拌处", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsFixtureService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureTypeController.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureTypeController.java
new file mode 100644
index 0000000..703fa39
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/controller/EimsFixtureTypeController.java
@@ -0,0 +1,117 @@
+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.EimsFixtureTypeVo;
+import org.dromara.eims.domain.bo.EimsFixtureTypeBo;
+import org.dromara.eims.service.IEimsFixtureTypeService;
+
+/**
+ * 宸ュ叿绫诲瀷
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/eims/fixtureType")
+public class EimsFixtureTypeController extends BaseController {
+
+    private final IEimsFixtureTypeService eimsFixtureTypeService;
+
+    /**
+     * 鏌ヨ宸ュ叿绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:fixtureType:list")
+    @GetMapping("/list")
+    public R<List<EimsFixtureTypeVo>> list(EimsFixtureTypeBo bo) {
+        List<EimsFixtureTypeVo> list = eimsFixtureTypeService.queryList(bo);
+        return R.ok(list);
+    }
+
+
+    /**
+     * 鑾峰彇璁惧绫诲瀷鏍戝垪琛�
+     */
+    @SaCheckPermission("eims:fixtureType:list")
+    @GetMapping("/tree")
+    public R<List<Tree<Long>>> fixtureTypeTree(EimsFixtureTypeBo bo) {
+        return R.ok(eimsFixtureTypeService.selectFixtureTypeTreeList(bo));
+    }
+
+    /**
+     * 瀵煎嚭宸ュ叿绫诲瀷鍒楄〃
+     */
+    @SaCheckPermission("eims:fixtureType:export")
+    @Log(title = "宸ュ叿绫诲瀷", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public  void export(EimsFixtureTypeBo bo, HttpServletResponse response) {
+        List<EimsFixtureTypeVo> list = eimsFixtureTypeService.queryList(bo);
+        ExcelUtil.exportExcel(list, "宸ュ叿绫诲瀷", EimsFixtureTypeVo.class, response);
+    }
+
+    /**
+     * 鑾峰彇宸ュ叿绫诲瀷璇︾粏淇℃伅
+     *
+     * @param id 涓婚敭
+     */
+    @SaCheckPermission("eims:fixtureType:query")
+    @GetMapping("/{id}")
+    public R<EimsFixtureTypeVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+                                     @PathVariable Long id) {
+        return R.ok(eimsFixtureTypeService.queryById(id));
+    }
+
+    /**
+     * 鏂板宸ュ叿绫诲瀷
+     */
+    @SaCheckPermission("eims:fixtureType:add")
+    @Log(title = "宸ュ叿绫诲瀷", businessType = BusinessType.INSERT)
+    @RepeatSubmit()
+    @PostMapping()
+    public R<Void> add(@Validated(AddGroup.class) @RequestBody EimsFixtureTypeBo bo) {
+        return toAjax(eimsFixtureTypeService.insertByBo(bo));
+    }
+
+    /**
+     * 淇敼宸ュ叿绫诲瀷
+     */
+    @SaCheckPermission("eims:fixtureType:edit")
+    @Log(title = "宸ュ叿绫诲瀷", businessType = BusinessType.UPDATE)
+    @RepeatSubmit()
+    @PutMapping()
+    public R<Void> edit(@Validated(EditGroup.class) @RequestBody EimsFixtureTypeBo bo) {
+        return toAjax(eimsFixtureTypeService.updateByBo(bo));
+    }
+
+    /**
+     * 鍒犻櫎宸ュ叿绫诲瀷
+     *
+     * @param ids 涓婚敭涓�
+     */
+    @SaCheckPermission("eims:fixtureType:remove")
+    @Log(title = "宸ュ叿绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{ids}")
+    public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+                          @PathVariable Long[] ids) {
+        return toAjax(eimsFixtureTypeService.deleteWithValidByIds(List.of(ids), true));
+    }
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixture.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixture.java
new file mode 100644
index 0000000..c821e00
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixture.java
@@ -0,0 +1,110 @@
+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_fixture
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_fixture")
+public class EimsFixture extends BaseEntity {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @TableId(value = "id")
+    private Long id;
+
+    /**
+     * 娌诲叿缂栫爜
+     */
+    private String fixtureCode;
+
+    /**
+     * 娌诲叿鍚嶇О
+     */
+    private String fixtureName;
+
+    /**
+     * 娌诲叿锛堝伐鍏凤級绫诲瀷
+     */
+    private Long fixtureType;
+
+    /**
+     * 娌诲叿鎻忚堪
+     */
+    private String fixtureDesc;
+
+    /**
+     * 鍊熺敤閮ㄩ棬
+     */
+    private Long borrowDept;
+
+    /**
+     * 鍊熺敤浜�
+     */
+    private Long borrowUser;
+
+    /**
+     * 鐘舵�侊紙瀛楀吀锛�
+     */
+    private String status;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    private String assetNo;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 瑙勬牸
+     */
+    private String specNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 浣跨敤鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    private Long serviceLife;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixtureType.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixtureType.java
new file mode 100644
index 0000000..95f0572
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/EimsFixtureType.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_fixture_type
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("eims_fixture_type")
+public class EimsFixtureType 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/EimsFixtureBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureBo.java
new file mode 100644
index 0000000..202a1fd
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureBo.java
@@ -0,0 +1,110 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsFixture;
+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_fixture
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsFixture.class, reverseConvertGenerate = false)
+public class EimsFixtureBo extends BaseEntity {
+
+    /**
+     *
+     */
+    @NotNull(message = "涓嶈兘涓虹┖", groups = { EditGroup.class })
+    private Long id;
+
+    /**
+     * 娌诲叿缂栫爜
+     */
+    private String fixtureCode;
+
+    /**
+     * 娌诲叿鍚嶇О
+     */
+    @NotBlank(message = "娌诲叿鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private String fixtureName;
+
+    /**
+     * 娌诲叿锛堝伐鍏凤級绫诲瀷
+     */
+    private Long fixtureType;
+
+    /**
+     * 娌诲叿鎻忚堪
+     */
+    private String fixtureDesc;
+
+    /**
+     * 鍊熺敤閮ㄩ棬
+     */
+    private Long borrowDept;
+
+    /**
+     * 鍊熺敤浜�
+     */
+    private Long borrowUser;
+
+    /**
+     * 鐘舵�侊紙瀛楀吀锛�
+     */
+    private String status;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    private String assetNo;
+
+    /**
+     * 鍨嬪彿
+     */
+    private String modelNo;
+
+    /**
+     * 瑙勬牸
+     */
+    private String specNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    private String madeIn;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 浣跨敤鏃ユ湡
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    private Long serviceLife;
+
+    /**
+     * 澶囨敞
+     */
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureTypeBo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureTypeBo.java
new file mode 100644
index 0000000..6470b1a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/bo/EimsFixtureTypeBo.java
@@ -0,0 +1,76 @@
+package org.dromara.eims.domain.bo;
+
+import org.dromara.eims.domain.EimsFixtureType;
+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_fixture_type
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = EimsFixtureType.class, reverseConvertGenerate = false)
+public class EimsFixtureTypeBo 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
+     */
+    @NotNull(message = "鐖秈d涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    private Long parentId;
+
+    /**
+     * 鏄剧ず椤哄簭
+     */
+    @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+    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/EimsEquTypeVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquTypeVo.java
index 7a3e36e..8c3081a 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquTypeVo.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsEquTypeVo.java
@@ -1,5 +1,6 @@
 package org.dromara.eims.domain.vo;
 
+import org.dromara.common.mybatis.core.domain.BaseEntity;
 import org.dromara.eims.domain.EimsEquType;
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
@@ -22,7 +23,7 @@
 @Data
 @ExcelIgnoreUnannotated
 @AutoMapper(target = EimsEquType.class)
-public class EimsEquTypeVo implements Serializable {
+public class EimsEquTypeVo extends BaseEntity implements Serializable {
 
     @Serial
     private static final long serialVersionUID = 1L;
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureTypeVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureTypeVo.java
new file mode 100644
index 0000000..0363993
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureTypeVo.java
@@ -0,0 +1,89 @@
+package org.dromara.eims.domain.vo;
+
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.eims.domain.EimsFixtureType;
+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_fixture_type
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsFixtureType.class)
+public class EimsFixtureTypeVo extends BaseEntity 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(dictType = "sys_show_hide")
+    private String status;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureVo.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureVo.java
new file mode 100644
index 0000000..86f6a85
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/domain/vo/EimsFixtureVo.java
@@ -0,0 +1,150 @@
+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.EimsFixture;
+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_fixture
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = EimsFixture.class)
+public class EimsFixtureVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     *
+     */
+    @ExcelProperty(value = "")
+    private Long id;
+
+    /**
+     * 娌诲叿缂栫爜
+     */
+    @ExcelProperty(value = "娌诲叿缂栫爜")
+    private String fixtureCode;
+
+    /**
+     * 娌诲叿鍚嶇О
+     */
+    @ExcelProperty(value = "娌诲叿鍚嶇О")
+    private String fixtureName;
+
+
+    /**
+     * 娌诲叿锛堝伐鍏凤級绫诲瀷
+     */
+    private Long fixtureType;
+
+    /**
+     * 娌诲叿锛堝伐鍏凤級绫诲瀷
+     */
+    @ExcelProperty(value = "娌诲叿绫诲瀷")
+    @Translation(type = TransConstant.FIXTURE_TYPE_ID_TO_NAME, mapper = "fixtureType")
+    private String fixtureTypeName;
+
+    /**
+     * 娌诲叿鎻忚堪
+     */
+    @ExcelProperty(value = "娌诲叿鎻忚堪")
+    private String fixtureDesc;
+
+    /**
+     * 鍊熺敤閮ㄩ棬
+     */
+    private Long borrowDept;
+
+    /**
+     * 鍊熺敤閮ㄩ棬
+     */
+    private String borrowDeptName;
+
+    /**
+     * 鍊熺敤浜�
+     */
+    private Long borrowUser;
+
+    /**
+     * 鍊熺敤浜�
+     */
+    private String borrowUserName;
+
+    /**
+     * 鐘舵�侊紙瀛楀吀锛�
+     */
+    @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(dictType = "eims_fixture_status")
+    private String status;
+
+    /**
+     * 璧勪骇缂栧彿
+     */
+    @ExcelProperty(value = "璧勪骇缂栧彿")
+    private String assetNo;
+
+    /**
+     * 鍨嬪彿
+     */
+    @ExcelProperty(value = "鍨嬪彿")
+    private String modelNo;
+
+    /**
+     * 瑙勬牸
+     */
+    @ExcelProperty(value = "瑙勬牸")
+    private String specNo;
+
+    /**
+     * 鍒堕�犲晢
+     */
+    @ExcelProperty(value = "鍒堕�犲晢")
+    private String madeIn;
+
+    /**
+     * 閲囪喘鏃ユ湡
+     */
+    @ExcelProperty(value = "閲囪喘鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date purchaseDate;
+
+    /**
+     * 浣跨敤鏃ユ湡
+     */
+    @ExcelProperty(value = "浣跨敤鏃ユ湡")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date deployDate;
+
+    /**
+     * 浣跨敤骞撮檺
+     */
+    @ExcelProperty(value = "浣跨敤骞撮檺")
+    private Long serviceLife;
+
+    /**
+     * 澶囨敞
+     */
+    @ExcelProperty(value = "澶囨敞")
+    private String remark;
+
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureMapper.java
new file mode 100644
index 0000000..70559fc
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsFixture;
+import org.dromara.eims.domain.vo.EimsFixtureVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 宸ュ叿(娌诲叿)鍙拌处Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+public interface EimsFixtureMapper extends BaseMapperPlus<EimsFixture, EimsFixtureVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureTypeMapper.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureTypeMapper.java
new file mode 100644
index 0000000..168bb9c
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/mapper/EimsFixtureTypeMapper.java
@@ -0,0 +1,15 @@
+package org.dromara.eims.mapper;
+
+import org.dromara.eims.domain.EimsFixtureType;
+import org.dromara.eims.domain.vo.EimsFixtureTypeVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 宸ュ叿绫诲瀷Mapper鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+public interface EimsFixtureTypeMapper extends BaseMapperPlus<EimsFixtureType, EimsFixtureTypeVo> {
+
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureService.java
new file mode 100644
index 0000000..b8e8121
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import org.dromara.eims.domain.vo.EimsFixtureVo;
+import org.dromara.eims.domain.bo.EimsFixtureBo;
+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-02-14
+ */
+public interface IEimsFixtureService {
+
+    /**
+     * 鏌ヨ宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param id 涓婚敭
+     * @return 宸ュ叿(娌诲叿)鍙拌处
+     */
+    EimsFixtureVo queryById(Long id);
+
+    /**
+     * 鍒嗛〉鏌ヨ宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 宸ュ叿(娌诲叿)鍙拌处鍒嗛〉鍒楄〃
+     */
+    TableDataInfo<EimsFixtureVo> queryPageList(EimsFixtureBo bo, PageQuery pageQuery);
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫伐鍏�(娌诲叿)鍙拌处鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     */
+    List<EimsFixtureVo> queryList(EimsFixtureBo bo);
+
+    /**
+     * 鏂板宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param bo 宸ュ叿(娌诲叿)鍙拌处
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsFixtureBo bo);
+
+    /**
+     * 淇敼宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param bo 宸ュ叿(娌诲叿)鍙拌处
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsFixtureBo 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/IEimsFixtureTypeService.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureTypeService.java
new file mode 100644
index 0000000..8da9689
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/IEimsFixtureTypeService.java
@@ -0,0 +1,68 @@
+package org.dromara.eims.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.eims.domain.bo.EimsEquTypeBo;
+import org.dromara.eims.domain.vo.EimsFixtureTypeVo;
+import org.dromara.eims.domain.bo.EimsFixtureTypeBo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 宸ュ叿绫诲瀷Service鎺ュ彛
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+public interface IEimsFixtureTypeService {
+
+    /**
+     * 鏌ヨ宸ュ叿绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 宸ュ叿绫诲瀷
+     */
+    EimsFixtureTypeVo queryById(Long id);
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫伐鍏风被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 宸ュ叿绫诲瀷鍒楄〃
+     */
+    List<EimsFixtureTypeVo> queryList(EimsFixtureTypeBo bo);
+
+    /**
+     * 鏂板宸ュ叿绫诲瀷
+     *
+     * @param bo 宸ュ叿绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    Boolean insertByBo(EimsFixtureTypeBo bo);
+
+    /**
+     * 淇敼宸ュ叿绫诲瀷
+     *
+     * @param bo 宸ュ叿绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    Boolean updateByBo(EimsFixtureTypeBo bo);
+
+    /**
+     * 鏍¢獙骞舵壒閲忓垹闄ゅ伐鍏风被鍨嬩俊鎭�
+     *
+     * @param ids     寰呭垹闄ょ殑涓婚敭闆嗗悎
+     * @param isValid 鏄惁杩涜鏈夋晥鎬ф牎楠�
+     * @return 鏄惁鍒犻櫎鎴愬姛
+     */
+    Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+    /**
+     * 鑾峰彇宸ュ叿绫诲瀷鏍戝垪琛�
+     *
+     * @param bo
+     * @return 鏍戝垪琛�
+     */
+    List<Tree<Long>> selectFixtureTypeTreeList(EimsFixtureTypeBo bo);
+}
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsEquTypeServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsEquTypeServiceImpl.java
index 13920e5..94bf12f 100644
--- a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsEquTypeServiceImpl.java
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsEquTypeServiceImpl.java
@@ -143,7 +143,7 @@
      */
     @Override
     public List<Tree<Long>> selectEquTypeTreeList(EimsEquTypeBo bo) {
-        // 鍙煡璇㈡湭绂佺敤閮ㄩ棬
+        // 鍙煡璇㈡湭绂佺敤绫诲瀷
         bo.setStatus(UserConstants.DEPT_NORMAL);
         LambdaQueryWrapper<EimsEquType> lqw = buildQueryWrapper(bo);
         List<EimsEquTypeVo> equTypeVoList = baseMapper.selectVoList(lqw);
diff --git a/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureServiceImpl.java
new file mode 100644
index 0000000..e6cf528
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureServiceImpl.java
@@ -0,0 +1,196 @@
+package org.dromara.eims.service.impl;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+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.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.EimsEqu;
+import org.dromara.eims.domain.EimsEquType;
+import org.dromara.eims.domain.EimsFixtureType;
+import org.dromara.eims.domain.vo.EimsEquTypeVo;
+import org.dromara.eims.domain.vo.EimsEquVo;
+import org.dromara.eims.domain.vo.EimsFixtureTypeVo;
+import org.dromara.eims.mapper.EimsFixtureTypeMapper;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsFixtureBo;
+import org.dromara.eims.domain.vo.EimsFixtureVo;
+import org.dromara.eims.domain.EimsFixture;
+import org.dromara.eims.mapper.EimsFixtureMapper;
+import org.dromara.eims.service.IEimsFixtureService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 宸ュ叿(娌诲叿)鍙拌处Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-02-14
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsFixtureServiceImpl implements IEimsFixtureService {
+
+    private final EimsFixtureMapper baseMapper;
+    private final EimsFixtureTypeMapper fixtureTypeMapper;
+
+    /**
+     * 鏌ヨ宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param id 涓婚敭
+     * @return 宸ュ叿(娌诲叿)鍙拌处
+     */
+    @Override
+    public EimsFixtureVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+    /**
+     * 鍒嗛〉鏌ヨ宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     *
+     * @param bo        鏌ヨ鏉′欢
+     * @param pageQuery 鍒嗛〉鍙傛暟
+     * @return 宸ュ叿(娌诲叿)鍙拌处鍒嗛〉鍒楄〃
+     */
+    @Override
+    public TableDataInfo<EimsFixtureVo> queryPageList(EimsFixtureBo bo, PageQuery pageQuery) {
+        LambdaQueryWrapper<EimsFixture> lqw = buildQueryWrapper(bo);
+        Page<EimsFixtureVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+        return TableDataInfo.build(result);
+    }
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫伐鍏�(娌诲叿)鍙拌处鍒楄〃
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 宸ュ叿(娌诲叿)鍙拌处鍒楄〃
+     */
+    @Override
+    public List<EimsFixtureVo> queryList(EimsFixtureBo bo) {
+        LambdaQueryWrapper<EimsFixture> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsFixture> buildQueryWrapper(EimsFixtureBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsFixture> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getFixtureCode()), EimsFixture::getFixtureCode, bo.getFixtureCode());
+        lqw.like(StringUtils.isNotBlank(bo.getFixtureName()), EimsFixture::getFixtureName, bo.getFixtureName());
+        Long fixtureType = bo.getFixtureType();
+        /**
+         * equTypeId = 0 鏃舵煡璇㈡墍鏈夎澶囷紙榛樿鏍圭洰褰昳d涓�0锛岃瑙丼ysEquTypeServiceImpl涓璼electEquTypeTreeList锛�
+         * equTypeId   涓哄叾浠栧�兼椂鍙煡褰撳墠璁惧绫诲瀷id鍜屽悗浠h澶囩被鍨媔d
+         */
+        if (fixtureType != null && fixtureType > 0) {
+            List<Long> allDescendantIds = getAllDescendantIds(fixtureType);
+            lqw.in(EimsFixture::getFixtureType, allDescendantIds);
+        }
+
+
+        lqw.eq(StringUtils.isNotBlank(bo.getFixtureDesc()), EimsFixture::getFixtureDesc, bo.getFixtureDesc());
+        lqw.eq(bo.getBorrowDept()!=null, EimsFixture::getBorrowDept, bo.getBorrowDept());
+        lqw.eq(bo.getBorrowUser()!=null, EimsFixture::getBorrowUser, bo.getBorrowUser());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), EimsFixture::getStatus, bo.getStatus());
+        lqw.like(StringUtils.isNotBlank(bo.getAssetNo()), EimsFixture::getAssetNo, bo.getAssetNo());
+        lqw.like(StringUtils.isNotBlank(bo.getModelNo()), EimsFixture::getModelNo, bo.getModelNo());
+        lqw.like(StringUtils.isNotBlank(bo.getSpecNo()), EimsFixture::getSpecNo, bo.getSpecNo());
+        lqw.like(StringUtils.isNotBlank(bo.getMadeIn()), EimsFixture::getMadeIn, bo.getMadeIn());
+        lqw.between(params.get("beginPurchaseDate") != null && params.get("endPurchaseDate") != null,
+            EimsFixture::getPurchaseDate ,params.get("beginPurchaseDate"), params.get("endPurchaseDate"));
+        lqw.between(params.get("beginDeployDate") != null && params.get("endDeployDate") != null,
+            EimsFixture::getDeployDate ,params.get("beginDeployDate"), params.get("endDeployDate"));
+        lqw.eq(bo.getServiceLife() != null, EimsFixture::getServiceLife, bo.getServiceLife());
+        return lqw;
+    }
+
+    /**
+     * 鏍规嵁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<EimsFixtureType> fixTypeWrapper = new QueryWrapper<>();
+        fixTypeWrapper.lambda().eq(EimsFixtureType::getParentId, currentId);
+
+        List<EimsFixtureTypeVo> children = fixtureTypeMapper.selectVoList(fixTypeWrapper);
+        if (children != null && !children.isEmpty()) {
+            for (EimsFixtureTypeVo child : children) {
+                Long childId = child.getId();
+                collector.add(childId);
+                collectDescendants(childId, collector);
+            }
+        }
+    }
+
+
+    /**
+     * 鏂板宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param bo 宸ュ叿(娌诲叿)鍙拌处
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsFixtureBo bo) {
+        EimsFixture add = MapstructUtils.convert(bo, EimsFixture.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼宸ュ叿(娌诲叿)鍙拌处
+     *
+     * @param bo 宸ュ叿(娌诲叿)鍙拌处
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsFixtureBo bo) {
+        EimsFixture update = MapstructUtils.convert(bo, EimsFixture.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsFixture 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/EimsFixtureTypeServiceImpl.java b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureTypeServiceImpl.java
new file mode 100644
index 0000000..e94f18a
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/java/org/dromara/eims/service/impl/EimsFixtureTypeServiceImpl.java
@@ -0,0 +1,183 @@
+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 org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.service.FixtureTypeService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.eims.domain.EimsEquType;
+import org.dromara.eims.domain.bo.EimsEquTypeBo;
+import org.dromara.eims.domain.vo.EimsEquTypeVo;
+import org.springframework.stereotype.Service;
+import org.dromara.eims.domain.bo.EimsFixtureTypeBo;
+import org.dromara.eims.domain.vo.EimsFixtureTypeVo;
+import org.dromara.eims.domain.EimsFixtureType;
+import org.dromara.eims.mapper.EimsFixtureTypeMapper;
+import org.dromara.eims.service.IEimsFixtureTypeService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * 宸ュ叿绫诲瀷Service涓氬姟灞傚鐞�
+ *
+ * @author zhuguifei
+ * @date 2025-02-17
+ */
+@RequiredArgsConstructor
+@Service
+public class EimsFixtureTypeServiceImpl implements IEimsFixtureTypeService, FixtureTypeService {
+
+    private final EimsFixtureTypeMapper baseMapper;
+
+    /**
+     * 鏌ヨ宸ュ叿绫诲瀷
+     *
+     * @param id 涓婚敭
+     * @return 宸ュ叿绫诲瀷
+     */
+    @Override
+    public EimsFixtureTypeVo queryById(Long id){
+        return baseMapper.selectVoById(id);
+    }
+
+
+    /**
+     * 鏌ヨ绗﹀悎鏉′欢鐨勫伐鍏风被鍨嬪垪琛�
+     *
+     * @param bo 鏌ヨ鏉′欢
+     * @return 宸ュ叿绫诲瀷鍒楄〃
+     */
+    @Override
+    public List<EimsFixtureTypeVo> queryList(EimsFixtureTypeBo bo) {
+        LambdaQueryWrapper<EimsFixtureType> lqw = buildQueryWrapper(bo);
+        return baseMapper.selectVoList(lqw);
+    }
+
+    private LambdaQueryWrapper<EimsFixtureType> buildQueryWrapper(EimsFixtureTypeBo bo) {
+        Map<String, Object> params = bo.getParams();
+        LambdaQueryWrapper<EimsFixtureType> lqw = Wrappers.lambdaQuery();
+        lqw.like(StringUtils.isNotBlank(bo.getTypeName()), EimsFixtureType::getTypeName, bo.getTypeName());
+        lqw.like(StringUtils.isNotBlank(bo.getTypeCode()), EimsFixtureType::getTypeCode, bo.getTypeCode());
+        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), EimsFixtureType::getStatus, bo.getStatus());
+        return lqw;
+    }
+
+    /**
+     * 鏂板宸ュ叿绫诲瀷
+     *
+     * @param bo 宸ュ叿绫诲瀷
+     * @return 鏄惁鏂板鎴愬姛
+     */
+    @Override
+    public Boolean insertByBo(EimsFixtureTypeBo bo) {
+        EimsFixtureType add = MapstructUtils.convert(bo, EimsFixtureType.class);
+        validEntityBeforeSave(add);
+        boolean flag = baseMapper.insert(add) > 0;
+        if (flag) {
+            bo.setId(add.getId());
+        }
+        return flag;
+    }
+
+    /**
+     * 淇敼宸ュ叿绫诲瀷
+     *
+     * @param bo 宸ュ叿绫诲瀷
+     * @return 鏄惁淇敼鎴愬姛
+     */
+    @Override
+    public Boolean updateByBo(EimsFixtureTypeBo bo) {
+        EimsFixtureType update = MapstructUtils.convert(bo, EimsFixtureType.class);
+        validEntityBeforeSave(update);
+        return baseMapper.updateById(update) > 0;
+    }
+
+    /**
+     * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+     */
+    private void validEntityBeforeSave(EimsFixtureType 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 List<Tree<Long>> selectFixtureTypeTreeList(EimsFixtureTypeBo bo) {
+        // 鍙煡璇㈡湭绂佺敤绫诲瀷
+        bo.setStatus(UserConstants.DEPT_NORMAL);
+        LambdaQueryWrapper<EimsFixtureType> lqw = buildQueryWrapper(bo);
+        List<EimsFixtureTypeVo> fixtureTypeVoList = baseMapper.selectVoList(lqw);
+
+        for (int i = 0; i < fixtureTypeVoList.size(); i++) {
+            EimsFixtureTypeVo fixtureTypeVo = fixtureTypeVoList.get(i);
+            if(fixtureTypeVo.getParentId() == null){
+                fixtureTypeVoList.get(i).setParentId(0L);
+            }
+        }
+        //鍔犳牴鐩綍
+        EimsFixtureTypeVo root = new EimsFixtureTypeVo();
+        root.setId(0L);
+        root.setMenuType("M");
+        root.setTypeName("鎵�鏈夊伐鍏�");
+        root.setStatus("0");
+        root.setTypeCode("0");
+        root.setOrderNum(0L);
+        root.setIcon("#");
+        fixtureTypeVoList.add(root);
+        fixtureTypeVoList.sort((o1, o2) -> o1.getId().compareTo(o2.getId()));
+        return buildEquTypeTreeSelect(fixtureTypeVoList);
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     *
+     * @param fixtureTypeVoList 宸ュ叿绫诲瀷鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    public List<Tree<Long>> buildEquTypeTreeSelect(List<EimsFixtureTypeVo> fixtureTypeVoList) {
+        if (CollUtil.isEmpty(fixtureTypeVoList)) {
+            return CollUtil.newArrayList();
+        }
+        return TreeBuildUtils.build(fixtureTypeVoList, (dept, tree) ->
+            tree.setId(dept.getId())
+                .setParentId(dept.getParentId())
+                .setName(dept.getTypeName())
+                .setWeight(dept.getOrderNum()));
+    }
+
+    @Override
+    public String selectFixtureTypeNameByIds(String fixIds) {
+        List<String> list = new ArrayList<>();
+        for (Long id : StringUtils.splitTo(fixIds, Convert::toLong)) {
+            EimsFixtureTypeVo 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/EimsFixtureMapper.xml b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFixtureMapper.xml
new file mode 100644
index 0000000..fe4abd8
--- /dev/null
+++ b/eims/ruoyi-modules/lb-eims/src/main/resources/mapper/eims/EimsFixtureMapper.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.EimsFixtureMapper">
+
+</mapper>

--
Gitblit v1.9.3