From 609b918b24e8dbbe75bf2eaef7a532308d83a708 Mon Sep 17 00:00:00 2001
From: zhuguifei <zhuguifei@zhuguifeideiMac.local>
Date: 星期三, 16 四月 2025 10:06:47 +0800
Subject: [PATCH] 完成备件模块

---
 eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue                                     |  110 +++++++
 eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue                                   |  122 +++++++
 eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/index.ts                                             |   61 ++++
 eims-ui/apps/web-antd/.env.production                                                                 |    4 
 eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue                                              |   25 +
 eims-ui/apps/web-antd/src/views/eims/spare-inoutdt/data.tsx                                           |   65 ++++
 eims-ui/apps/web-antd/src/api/eims/spare/index.ts                                                     |    5 
 eims-ui/apps/web-antd/src/views/eims/components/basis-sub-table.vue                                   |    1 
 eims/ruoyi-admin/src/main/resources/application-prod.yml                                              |    6 
 eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts                                             |    9 
 eims-ui/apps/web-antd/src/views/eims/components/spare-modal.vue                                       |   54 +++
 eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java |   12 
 eims-ui/apps/web-antd/src/views/eims/spare/data.tsx                                                   |   89 +++++
 eims-ui/apps/web-antd/src/views/eims/spare-out/select-spare-table.vue                                 |  121 ++++++++
 eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/model.d.ts                                           |   46 +++
 eims-ui/apps/web-antd/src/views/eims/spare/index.vue                                                  |   98 +++--
 eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue                                               |   25 +
 eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx                                               |   13 
 eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx                                                |   11 
 19 files changed, 809 insertions(+), 68 deletions(-)

diff --git a/eims-ui/apps/web-antd/.env.production b/eims-ui/apps/web-antd/.env.production
index 4086f92..00537ff 100644
--- a/eims-ui/apps/web-antd/.env.production
+++ b/eims-ui/apps/web-antd/.env.production
@@ -19,7 +19,7 @@
 VITE_GLOB_API_URL=/prod-api
 
 # 鍏ㄥ眬鍔犲瘑寮�鍏�(鍗冲紑鍚簡鍔犺В瀵嗗姛鑳芥墠浼氱敓鏁� 涓嶆槸鍏ㄩ儴鎺ュ彛鍔犲瘑 闇�瑕佸拰鍚庣瀵瑰簲)
-VITE_GLOB_ENABLE_ENCRYPT=true
+VITE_GLOB_ENABLE_ENCRYPT=false
 # RSA鍏挜 璇锋眰鍔犲瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
 VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
 # RSA绉侀挜 鍝嶅簲瑙e瘑浣跨敤 娉ㄦ剰杩欎袱涓槸涓ゅRSA鍏閽� 璇锋眰鍔犲瘑-鍚庣瑙e瘑鏄竴瀵� 鍝嶅簲瑙e瘑-鍚庣鍔犲瘑鏄竴瀵�
@@ -28,5 +28,5 @@
 VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
 
 # 寮�鍚疭SE
-VITE_GLOB_SSE_ENABLE=true
+VITE_GLOB_SSE_ENABLE=false
 
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts
index ae55af8..22e1665 100644
--- a/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-inout/model.d.ts
@@ -20,6 +20,11 @@
   chargeUser: number;
 
   /**
+   * 缁忓姙閮ㄩ棬
+   */
+  chargeDept: number;
+
+  /**
    * 宸ュ崟绫诲瀷锛�1-鍏ュ簱鍗�  2-鍑哄簱鍗曪級 瀛楀吀
    */
   type: string;
@@ -38,4 +43,8 @@
    * 澶囨敞
    */
   remark: string;
+  /**
+   * 鍑哄叆搴撻�夋嫨鐨勫浠跺垪琛�
+   */
+  spareList: any;
 }
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/index.ts b/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/index.ts
new file mode 100644
index 0000000..712f532
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/index.ts
@@ -0,0 +1,61 @@
+import type { IDS, PageQuery, PageResult } from '#/api/common';
+import type { SpareInoutdtVO } from '#/api/eims/spare-inoutdt/model';
+
+import { commonExport } from '#/api/helper';
+import { requestClient } from '#/api/request';
+
+enum Api {
+  root = '/eims/spareInoutdt',
+  spareInoutdtExport = '/eims/spareInoutdt/export',
+  spareInoutdtList = '/eims/spareInoutdt/list'
+}
+
+/**
+ * 鏌ヨ銆愬浠跺嚭鍏ュ簱鏄庣粏銆戝垪琛�
+ * @param query
+ * @returns {*}
+ */
+
+export function listSpareInoutdt(params?: PageQuery) {
+  return requestClient.get<PageResult<SpareInoutdtVO>>(Api.spareInoutdtList, { params });
+}
+
+/**
+ * 鏌ヨ銆愬浠跺嚭鍏ュ簱鏄庣粏銆戣缁�
+ * @param spareInoutdtId
+ */
+export function getSpareInoutdt(spareInoutdtId: any) {
+  return requestClient.get<SpareInoutdtVO>(`${Api.root}/${spareInoutdtId}`);
+}
+
+/**
+ * 鏂板銆愬浠跺嚭鍏ュ簱鏄庣粏銆�
+ * @param data
+ */
+export function addSpareInoutdt(data: any) {
+  return requestClient.postWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 淇敼銆愬浠跺嚭鍏ュ簱鏄庣粏銆�
+ * @param data
+ */
+export function updateSpareInoutdt(data: any) {
+  return requestClient.putWithMsg<void>(Api.root, data);
+}
+
+/**
+ * 鍒犻櫎銆愬浠跺嚭鍏ュ簱鏄庣粏銆�
+ * @param spareInoutdtIds
+ */
+export function delSpareInoutdt(spareInoutdtIds: IDS) {
+  return requestClient.deleteWithMsg<void>(`${Api.root}/${spareInoutdtIds}`);
+}
+
+/**
+ * 瀵煎嚭銆愬浠跺嚭鍏ュ簱鏄庣粏銆�
+ * @param data
+ */
+export function spareInoutdtExport(data: any) {
+  return commonExport(Api.spareInoutdtExport, data);
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/model.d.ts b/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/model.d.ts
new file mode 100644
index 0000000..b2759f2
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/api/eims/spare-inoutdt/model.d.ts
@@ -0,0 +1,46 @@
+export interface SpareInoutdtVO {
+  /**
+   *
+   */
+  id: number | string;
+
+  /**
+   * 鍑哄簱鍗曟垨鍏ュ簱鍗昳d
+   */
+  inoutId: number | string;
+
+  /**
+   * 澶囦欢id
+   */
+  spareId: number | string;
+
+  /**
+   * 涔嬪墠搴撳瓨
+   */
+  beforeStock: number;
+
+  /**
+   * 瀹為檯搴撳瓨
+   */
+  actualStock: number;
+
+  /**
+   * 鏁伴噺
+   */
+  quantity: number;
+
+  /**
+   * 鍗曚环
+   */
+  unitPrice: number;
+
+  /**
+   * 閲戦
+   */
+  amount: number;
+
+  /**
+   * 澶囨敞
+   */
+  remark: string;
+}
diff --git a/eims-ui/apps/web-antd/src/api/eims/spare/index.ts b/eims-ui/apps/web-antd/src/api/eims/spare/index.ts
index b5886ed..2fb6930 100644
--- a/eims-ui/apps/web-antd/src/api/eims/spare/index.ts
+++ b/eims-ui/apps/web-antd/src/api/eims/spare/index.ts
@@ -5,6 +5,7 @@
 import { requestClient } from '#/api/request';
 
 enum Api {
+  inoutList = '/eims/spare/listInout',
   root = '/eims/spare',
   spareExport = '/eims/spare/export',
   spareList = '/eims/spare/list'
@@ -20,6 +21,10 @@
   return requestClient.get<PageResult<SpareVO>>(Api.spareList, { params });
 }
 
+export function listInout(params?: PageQuery) {
+  return requestClient.get<PageResult<any>>(Api.inoutList, { params });
+}
+
 /**
  * 鏌ヨ銆愬浠跺彴璐︺�戣缁�
  * @param spareId
diff --git a/eims-ui/apps/web-antd/src/views/eims/components/basis-sub-table.vue b/eims-ui/apps/web-antd/src/views/eims/components/basis-sub-table.vue
index d2d3732..7487ac4 100644
--- a/eims-ui/apps/web-antd/src/views/eims/components/basis-sub-table.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/components/basis-sub-table.vue
@@ -16,6 +16,7 @@
 const columns = props?.columns?.filter((i) => i.field !== 'action');
 
 const gridOptions: VxeGridProps = {
+  size: 'mini',
   checkboxConfig: {
     // 楂樹寒
     highlight: true,
diff --git a/eims-ui/apps/web-antd/src/views/eims/components/spare-modal.vue b/eims-ui/apps/web-antd/src/views/eims/components/spare-modal.vue
new file mode 100644
index 0000000..e282745
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/components/spare-modal.vue
@@ -0,0 +1,54 @@
+<script setup lang="ts">
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { ref } from 'vue';
+
+import { useVbenModal } from '@vben/common-ui';
+import { DictEnum } from '@vben/constants';
+
+import { message } from 'ant-design-vue';
+
+import { renderDict } from '#/utils/render';
+import InnerView from '#/views/eims/spare/index.vue';
+
+const emit = defineEmits<{ updateSelect: [any] }>();
+
+const [BasicModal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  draggable: true,
+  onCancel: handleCancel,
+  onConfirm: handleConfirm
+});
+const innerView = ref();
+
+async function handleConfirm() {
+  try {
+    modalApi.modalLoading(true);
+    const tableSelect = innerView.value.tableSelect();
+    const eList = tableSelect.filter((item: any) => !item.actualStock && item.actualStock <= 0);
+    // 妫�娴嬮�夋嫨鐨勫浠跺簱瀛樻槸鍚︽甯�
+    if (eList.length > 0) {
+      message.error('瀛樺湪搴撳瓨涓嶈冻澶囦欢锛岃閲嶆柊閫夋嫨');
+      return false;
+    }
+    emit('updateSelect', tableSelect);
+    await handleCancel();
+  } catch (error) {
+    console.error(error);
+  } finally {
+    modalApi.modalLoading(false);
+  }
+}
+
+async function handleCancel() {
+  modalApi.close();
+}
+</script>
+
+<template>
+  <BasicModal :fullscreen-button="true" class="w-[800px]">
+    <InnerView ref="innerView" />
+  </BasicModal>
+</template>
+
+<style scoped></style>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx
index 3d02eb4..aa0b0c5 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/data.tsx
@@ -118,6 +118,17 @@
     label: '渚涘簲鍟�'
   },
   {
+    component: 'Input',
+    fieldName: 'openSpare',
+    label: '閫夋嫨澶囦欢',
+    formItemClass: 'col-span-1 w-[80px]'
+  },
+  {
+    component: 'Input',
+    fieldName: 'outSpareList',
+    label: ''
+  },
+  {
     component: 'TreeSelect',
     // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
     defaultValue: undefined,
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue
index 7a054c4..f2f8183 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/index.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { Recordable } from '@vben/types';
 
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 
 import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
 import { $t } from '@vben/locales';
@@ -16,6 +16,9 @@
 
 import { columns, querySchema } from './data';
 import drawer from './spare-in-drawer.vue';
+import { columns as inoutCol } from '#/views/eims/spare-inoutdt/data';
+import { listSpareInoutdt } from '#/api/eims/spare-inoutdt';
+import BasisSubTable from '#/views/eims/components/basis-sub-table.vue';
 
 const formOptions: VbenFormProps = {
   commonConfig: {
@@ -69,12 +72,16 @@
   },
   id: 'spre-inout-index'
 };
-
+const inoutId = ref<string>();
 const [BasicTable, tableApi] = useVbenVxeGrid({
   formOptions,
   gridOptions,
   gridEvents: {
-    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+    cellClick: (e: any) => {
+      const { row } = e;
+      inoutId.value = row.id;
+    }
   }
 });
 
@@ -190,8 +197,8 @@
 
 <template>
   <Page :auto-content-height="true">
-    <div class="flex h-full gap-[8px]">
-      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍏ュ簱鍗曞垪琛�">
+    <div class="flex h-full gap-[8px] flex-col">
+      <BasicTable class="h-2/3" table-title="澶囦欢鍏ュ簱鍗曞垪琛�">
         <template #toolbar-tools>
           <Space>
             <a-button v-access:code="['eims:spareInout:export']" @click="handleDownloadExcel">
@@ -231,6 +238,14 @@
           </Space>
         </template>
       </BasicTable>
+      <BasisSubTable
+        :columns="inoutCol"
+        :list-api="listSpareInoutdt"
+        :req-value="inoutId"
+        class="h-1/3"
+        req-key="inoutId"
+        title="鍏ュ簱鏄庣粏"
+      />
     </div>
     <Drawer @reload="tableApi.query()" />
   </Page>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue
index 263c7ac..919183e 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-in/spare-in-drawer.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import { computed, ref } from 'vue';
 
-import { useVbenDrawer } from '@vben/common-ui';
+import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
 import { $t } from '@vben/locales';
 import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
 
@@ -11,7 +11,72 @@
 
 import { drawerSchema } from './data';
 import CodeInput from '#/views/eims/components/code-input.vue';
+import spareModal from '#/views/eims/components/spare-modal.vue';
+import SelectSpareTable from '#/views/eims/spare-out/select-spare-table.vue';
+import { message } from 'ant-design-vue';
+import type { VxeGridProps } from '#/adapter/vxe-table';
+import { renderDict } from '#/utils/render';
+import { DictEnum } from '@vben/constants';
+/**
+ * 鍑哄簱鍗曢�夋嫨鐨勫浠舵暟鎹�
+ */
+const outSpareList = ref([]);
+const selectSpareTable = ref();
+const outCol: VxeGridProps['columns'] = [
+  {
+    field: 'action',
+    slots: { default: 'action' },
+    title: '鍒犻櫎',
+    width: 60
+  },
+  {
+    title: '澶囦欢鍚嶇О',
+    field: 'name',
+    width: 180
+  },
+  {
+    title: '澶囦欢缂栫爜',
+    field: 'code',
+    width: 120
+  },
+  {
+    title: '澶囦欢鍨嬪彿',
+    field: 'modelNo',
+    width: 100
+  },
+  {
+    title: '璁¢噺鍗曚綅',
+    field: 'unit',
+    slots: {
+      default: ({ row }) => {
+        if (!row.unit || row.unit === '') {
+          return '';
+        }
+        return renderDict(row.unit, DictEnum.EIMS_SPARE_UNIT);
+      }
+    },
+    width: 80
+  },
 
+  {
+    title: '瀹為檯搴撳瓨',
+    field: 'actualStock',
+    width: 100
+  },
+  {
+    title: '鏁伴噺',
+    field: 'quantity',
+    editRender: {
+      name: 'input'
+    },
+    width: 80
+  },
+  {
+    title: '鍙傝�冧环',
+    field: 'referPrice',
+    width: 90
+  }
+];
 const emit = defineEmits<{ reload: [] }>();
 
 const isUpdate = ref(false);
@@ -39,6 +104,7 @@
     if (!isOpen) {
       return null;
     }
+    outSpareList.value = [];
     drawerApi.drawerLoading(true);
     const { id } = drawerApi.getData() as { id?: number | string };
     isUpdate.value = !!id;
@@ -48,6 +114,10 @@
     if (isUpdate.value && id) {
       const record = await getSpareInout(id);
       await formApi.setValues(record);
+      outSpareList.value = record?.spareList;
+      if (isUpdate.value && record.chargeDept) {
+        await setupUserOptions(record.chargeDept);
+      }
     }
 
     drawerApi.drawerLoading(false);
@@ -127,7 +197,15 @@
     if (!valid) {
       return;
     }
+    const selectSpareList = selectSpareTable.value.tableData();
+    // 妫�娴嬫槸鍚﹁緭鍏ュ嚭搴撴暟閲�
+    const eList = selectSpareList.filter((item: any) => !item.quantity || item.quantity <= 0);
+    if (selectSpareList.length<= 0 || eList.length > 0) {
+      message.error('鍏ュ簱鏁伴噺涓虹┖锛岃妫�鏌ワ紒');
+      return false;
+    }
     const data = cloneDeep(await formApi.getValues());
+    data.spareList = selectSpareList;
     await (isUpdate.value ? updateSpareInout(data) : addSpareInout(data));
     emit('reload');
     await handleCancel();
@@ -142,14 +220,42 @@
   drawerApi.close();
   await formApi.resetForm();
 }
+
+// 澶囦欢modal
+const [SpareModal, spareModalApi] = useVbenModal({
+  connectedComponent: spareModal,
+  draggable: true,
+  title: '閫夋嫨澶囦欢'
+});
+
+function handleSpareModal() {
+  spareModalApi.setData({});
+  spareModalApi.open();
+}
+
+/**
+ * 閫夋嫨鐨勫浠�
+ * @param spareList
+ */
+function selectSpare(spareList: any) {
+  outSpareList.value = spareList;
+}
 </script>
 
 <template>
-  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[1000px]">
     <BasicForm>
       <template #orderCode="slotProps">
         <CodeInput v-bind="slotProps" :disabled="isUpdate" prefix="RK" />
       </template>
+      <template #openSpare="slotProps">
+        <a-button type="primary" v-bind="slotProps" :disabled="isUpdate" @click.stop="handleSpareModal">娣诲姞澶囦欢</a-button>
+      </template>
+      <template #outSpareList>
+        <SelectSpareTable ref="selectSpareTable" :columns="outCol" :data="outSpareList" :is-update="isUpdate" />
+      </template>
     </BasicForm>
+
+    <SpareModal class="w-[1200px]" @update-select="selectSpare" />
   </BasicDrawer>
 </template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-inoutdt/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-inoutdt/data.tsx
new file mode 100644
index 0000000..d205daf
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-inoutdt/data.tsx
@@ -0,0 +1,65 @@
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
+import { type FormSchemaGetter } from '#/adapter/form';
+import { renderDict } from '#/utils/render';
+import { DictEnum } from '@vben/constants';
+export const querySchema: FormSchemaGetter = () => [];
+
+export const columns: VxeGridProps['columns'] = [
+  { type: 'checkbox', width: 60, fixed: 'left' },
+  {
+    title: '澶囦欢鍚嶇О',
+    field: 'spareName',
+    minWidth: 120
+  },
+  {
+    title: '澶囦欢缂栧彿',
+    field: 'spareCode',
+    minWidth: 120
+  },
+  {
+    title: '瑙勬牸鍨嬪彿',
+    field: 'modelNo',
+    minWidth: 100
+  },
+  {
+    title: '璁¢噺鍗曚綅',
+    field: 'unit',
+    sortable: true,
+    slots: {
+      default: ({ row }) => {
+        if (!row.unit || row.unit === '') {
+          return '';
+        }
+        return renderDict(row.unit, DictEnum.EIMS_SPARE_UNIT);
+      }
+    },
+    width: 100
+  },
+  {
+    title: '涔嬪墠搴撳瓨',
+    field: 'beforeStock',
+    minWidth: 100
+  },
+  {
+    title: '褰撳墠搴撳瓨',
+    field: 'actualStock',
+    minWidth: 100
+  },
+  {
+    title: '鏁伴噺',
+    field: 'quantity',
+    minWidth: 80
+  },
+  {
+    title: '鍗曚环',
+    field: 'unitPrice',
+    minWidth: 80
+  },
+  {
+    title: '閲戦',
+    field: 'amount',
+    minWidth: 80
+  }
+];
+export const drawerSchema: FormSchemaGetter = () => [];
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx
index dd1dbc0..9b09695 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/data.tsx
@@ -84,6 +84,8 @@
   }
 ];
 
+
+
 export const drawerSchema: FormSchemaGetter = () => [
   {
     component: 'Input',
@@ -118,6 +120,17 @@
     label: '瀹㈡埛'
   },
   {
+    component: 'Input',
+    fieldName: 'openSpare',
+    label: '閫夋嫨澶囦欢',
+    formItemClass: 'col-span-1 w-[80px]'
+  },
+  {
+    component: 'Input',
+    fieldName: 'outSpareList',
+    label: ''
+  },
+  {
     component: 'TreeSelect',
     // 鍦╠rawer閲屾洿鏂� 杩欓噷涓嶉渶瑕侀粯璁ょ殑componentProps
     defaultValue: undefined,
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue
index 764ec4a..fb9b3b9 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/index.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { Recordable } from '@vben/types';
 
-import { onMounted } from 'vue';
+import { onMounted, ref } from 'vue';
 
 import { Page, useVbenDrawer, type VbenFormProps } from '@vben/common-ui';
 import { $t } from '@vben/locales';
@@ -16,6 +16,9 @@
 
 import { columns, querySchema } from './data';
 import drawer from './spare-out-drawer.vue';
+import { columns as inoutCol } from '#/views/eims/spare-inoutdt/data';
+import { listSpareInoutdt } from '#/api/eims/spare-inoutdt';
+import BasisSubTable from '#/views/eims/components/basis-sub-table.vue';
 
 const formOptions: VbenFormProps = {
   commonConfig: {
@@ -69,12 +72,16 @@
   },
   id: 'spre-inout-index'
 };
-
+const inoutId = ref<string>();
 const [BasicTable, tableApi] = useVbenVxeGrid({
   formOptions,
   gridOptions,
   gridEvents: {
-    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+    cellClick: (e: any) => {
+      const { row } = e;
+      inoutId.value = row.id;
+    }
   }
 });
 
@@ -190,8 +197,8 @@
 
 <template>
   <Page :auto-content-height="true">
-    <div class="flex h-full gap-[8px]">
-      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍑哄簱鍗曞垪琛�">
+    <div class="flex h-full gap-[8px] flex-col">
+      <BasicTable class="h-2/3" table-title="澶囦欢鍑哄簱鍗曞垪琛�">
         <template #toolbar-tools>
           <Space>
             <a-button v-access:code="['eims:spareInout:export']" @click="handleDownloadExcel">
@@ -231,6 +238,14 @@
           </Space>
         </template>
       </BasicTable>
+      <BasisSubTable
+        :columns="inoutCol"
+        :list-api="listSpareInoutdt"
+        :req-value="inoutId"
+        class="h-1/3"
+        req-key="inoutId"
+        title="鍑哄簱鏄庣粏"
+      />
     </div>
     <Drawer @reload="tableApi.query()" />
   </Page>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/select-spare-table.vue b/eims-ui/apps/web-antd/src/views/eims/spare-out/select-spare-table.vue
new file mode 100644
index 0000000..a84011c
--- /dev/null
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/select-spare-table.vue
@@ -0,0 +1,121 @@
+<script setup lang="ts">
+import type { Recordable } from '@vben/types';
+
+import { reactive, ref, watch } from 'vue';
+
+import { $t } from '@vben/locales';
+import { getVxePopupContainer } from '@vben/utils';
+
+import { Popconfirm, Space } from 'ant-design-vue';
+
+import { useVbenVxeGrid, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
+
+
+interface Props {
+  title?: string;
+  columns?: VxeGridProps['columns'];
+  data: any;
+  isUpdate?: boolean;
+}
+const props = defineProps<Props>();
+
+const responsiveData = reactive(props.data);
+defineExpose({
+  tableData
+});
+
+watch(
+  () => props.data,
+  (data) => {
+    responsiveData.splice(0, responsiveData.length, ...data);
+  }
+);
+
+const gridOptions: VxeGridProps = {
+  checkboxConfig: {
+    // 楂樹寒
+    highlight: true,
+    // 缈婚〉鏃朵繚鐣欓�変腑鐘舵��
+    reserve: true
+    // 鐐瑰嚮琛岄�変腑
+    // trigger: 'row'
+  },
+  columns: props.columns,
+  height: 'auto',
+  keepSource: true,
+  data: responsiveData,
+  pagerConfig: {
+    enabled: false
+  },
+  toolbarConfig: {
+    enabled: false
+  },
+  rowConfig: {
+    isHover: true,
+    keyField: 'id'
+  },
+  sortConfig: {
+    // 杩滅▼鎺掑簭
+    remote: true,
+    // 鏀寔澶氬瓧娈垫帓搴� 榛樿鍏抽棴
+    multiple: true
+  },
+  editConfig: {
+    mode: 'cell',
+    trigger: 'click'
+  },
+  id: 'local-table'
+};
+
+const [BasicTable, tableApi] = useVbenVxeGrid({
+  gridOptions,
+  gridEvents: {
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+  }
+});
+
+function handleDelete(row: Recordable<any>) {
+  const index = responsiveData.findIndex((item: any) => item.id === row.id);
+  if (index !== -1) {
+    responsiveData.splice(index, 1);
+  }
+}
+// 閫変腑鏁版嵁
+function tableData() {
+  return tableApi.grid.getData();
+}
+
+
+/**
+ * TODO 鍚庣画鎵╁睍鐐瑰嚮浜嬩欢
+ */
+const slotName = ref<string>('equName');
+</script>
+
+<template>
+  <div class="w-full h-min">
+    <BasicTable :table-title="title" size="small">
+      <template #[slotName]="{ row }">
+        <Space>
+          <span>{{ row[slotName] }}</span>
+        </Space>
+      </template>
+
+      <template #action="{ row }">
+        <Space>
+          <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+            <ghost-button :disabled="isUpdate" danger @click.stop="">
+              {{ $t('pages.common.delete') }}
+            </ghost-button>
+          </Popconfirm>
+        </Space>
+      </template>
+    </BasicTable>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+:deep(.p-2) {
+  padding: 0;
+}
+</style>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue b/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue
index ebd82a4..8d4219c 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/spare-out/spare-out-drawer.vue
@@ -1,18 +1,88 @@
 <script setup lang="ts">
+import type { VxeGridProps } from '#/adapter/vxe-table';
+
 import { computed, ref } from 'vue';
 
-import { useVbenDrawer } from '@vben/common-ui';
+import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
+import { DictEnum } from '@vben/constants';
 import { $t } from '@vben/locales';
 import { addFullName, cloneDeep, getPopupContainer } from '@vben/utils';
+
+import { message } from 'ant-design-vue';
 
 import { useVbenForm } from '#/adapter/form';
 import { addSpareInout, getSpareInout, updateSpareInout } from '#/api/eims/spare-inout';
 import { getDeptTree, userList } from '#/api/system/user';
+import { renderDict } from '#/utils/render';
+import CodeInput from '#/views/eims/components/code-input.vue';
+import spareModal from '#/views/eims/components/spare-modal.vue';
 
 import { drawerSchema } from './data';
-import CodeInput from '#/views/eims/components/code-input.vue';
+import SelectSpareTable from './select-spare-table.vue';
 
 const emit = defineEmits<{ reload: [] }>();
+
+/**
+ * 鍑哄簱鍗曢�夋嫨鐨勫浠舵暟鎹�
+ */
+const outSpareList = ref([]);
+const selectSpareTable = ref();
+
+const outCol: VxeGridProps['columns'] = [
+  {
+    field: 'action',
+    slots: { default: 'action' },
+    title: '鍒犻櫎',
+    width: 60
+  },
+  {
+    title: '澶囦欢鍚嶇О',
+    field: 'name',
+    width: 180
+  },
+  {
+    title: '澶囦欢缂栫爜',
+    field: 'code',
+    width: 120
+  },
+  {
+    title: '澶囦欢鍨嬪彿',
+    field: 'modelNo',
+    width: 100
+  },
+  {
+    title: '璁¢噺鍗曚綅',
+    field: 'unit',
+    slots: {
+      default: ({ row }) => {
+        if (!row.unit || row.unit === '') {
+          return '';
+        }
+        return renderDict(row.unit, DictEnum.EIMS_SPARE_UNIT);
+      }
+    },
+    width: 80
+  },
+
+  {
+    title: '瀹為檯搴撳瓨',
+    field: 'actualStock',
+    width: 100
+  },
+  {
+    title: '鏁伴噺',
+    field: 'quantity',
+    editRender: {
+      name: 'input'
+    },
+    width: 80
+  },
+  {
+    title: '鍙傝�冧环',
+    field: 'referPrice',
+    width: 90
+  }
+];
 
 const isUpdate = ref(false);
 const title = computed(() => {
@@ -42,12 +112,18 @@
     drawerApi.drawerLoading(true);
     const { id } = drawerApi.getData() as { id?: number | string };
     isUpdate.value = !!id;
+    outSpareList.value = [];
     // 鍒濆鍖�
     await setupDeptSelect();
     // 鏇存柊 && 璧嬪��
     if (isUpdate.value && id) {
       const record = await getSpareInout(id);
       await formApi.setValues(record);
+      // 鏇存柊鍑哄簱鍗曠殑澶囦欢鏄庣粏
+      outSpareList.value = record?.spareList;
+      if (isUpdate.value && record.chargeDept) {
+        await setupUserOptions(record.chargeDept);
+      }
     }
 
     drawerApi.drawerLoading(false);
@@ -104,7 +180,7 @@
           /** 鏍规嵁閮ㄩ棬ID鍔犺浇鐢ㄦ埛 */
           await setupUserOptions(deptId);
           /** 鍙樺寲鍚庨渶瑕侀噸鏂伴�夋嫨鐢ㄦ埛 */
-          formModel.operatorId = undefined;
+          formModel.chargeUser = undefined;
         },
         placeholder: '璇烽�夋嫨',
         showSearch: true,
@@ -120,6 +196,7 @@
     }
   ]);
 }
+
 async function handleConfirm() {
   try {
     drawerApi.drawerLoading(true);
@@ -127,7 +204,15 @@
     if (!valid) {
       return;
     }
+    const selectSpareList = selectSpareTable.value.tableData();
+    // 妫�娴嬫槸鍚﹁緭鍏ュ嚭搴撴暟閲�
+    const eList = selectSpareList.filter((item: any) => !item.quantity || item.quantity <= 0 || item.quantity > item.actualStock);
+    if (selectSpareList.length<= 0 ||eList.length > 0) {
+      message.error('鍑哄簱鏁伴噺涓虹┖鎴栧ぇ浜庡簱瀛橈紝璇锋鏌ワ紒');
+      return false;
+    }
     const data = cloneDeep(await formApi.getValues());
+    data.spareList = selectSpareList;
     await (isUpdate.value ? updateSpareInout(data) : addSpareInout(data));
     emit('reload');
     await handleCancel();
@@ -142,14 +227,43 @@
   drawerApi.close();
   await formApi.resetForm();
 }
+
+// 澶囦欢modal
+const [SpareModal, spareModalApi] = useVbenModal({
+  connectedComponent: spareModal,
+  draggable: true,
+  title: '閫夋嫨澶囦欢'
+});
+
+function handleSpareModal() {
+  spareModalApi.setData({});
+  spareModalApi.open();
+}
+
+/**
+ * 閫夋嫨鐨勫浠�
+ * @param spareList
+ */
+function selectSpare(spareList: any) {
+  outSpareList.value = spareList;
+}
 </script>
 
 <template>
-  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[600px]">
+  <BasicDrawer :close-on-click-modal="false" :title="title" class="w-[1000px]">
     <BasicForm>
       <template #orderCode="slotProps">
         <CodeInput v-bind="slotProps" :disabled="isUpdate" prefix="CK" />
       </template>
+
+      <template #openSpare="slotProps">
+        <a-button type="primary" v-bind="slotProps" :disabled="isUpdate" @click.stop="handleSpareModal">娣诲姞澶囦欢</a-button>
+      </template>
+
+      <template #outSpareList>
+        <SelectSpareTable ref="selectSpareTable" :columns="outCol" :data="outSpareList" :is-update="isUpdate" />
+      </template>
     </BasicForm>
+    <SpareModal class="w-[1200px]" @update-select="selectSpare" />
   </BasicDrawer>
 </template>
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx b/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx
index 8228ae6..709705a 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/data.tsx
@@ -1,11 +1,13 @@
 import type { VxeGridProps } from '#/adapter/vxe-table';
 
 import { DictEnum } from '@vben/constants';
+import { getPopupContainer } from '@vben/utils';
+
+import { Tag } from 'ant-design-vue';
 
 import { type FormSchemaGetter } from '#/adapter/form';
 import { getDictOptions } from '#/utils/dict';
 import { renderDict } from '#/utils/render';
-import { getPopupContainer } from '@vben/utils';
 
 export const querySchema: FormSchemaGetter = () => [
   {
@@ -84,7 +86,7 @@
     sortable: true,
     slots: {
       default: ({ row }) => {
-        if (row.unit === null || row.unit === '') {
+        if (!row.unit || row.unit === '') {
           return '';
         }
         return renderDict(row.unit, DictEnum.EIMS_SPARE_UNIT);
@@ -138,6 +140,87 @@
   }
 ];
 
+export const inoutCol: VxeGridProps['columns'] = [
+  {
+    title: '鍑哄叆搴撳崟鍙�',
+    field: 'orderCode',
+    width: 180
+  },
+  {
+    title: '鏃ユ湡',
+    field: 'orderTime',
+    width: 180
+  },
+  {
+    title: '鏂瑰悜',
+    field: 'type1',
+    width: 80,
+    slots: {
+      default: ({ row }) => {
+        const type = row.type;
+        switch (type) {
+          case '1': {
+            return <Tag color="green"> 鍏ュ簱 </Tag>;
+          }
+          case '2': {
+            return <Tag color="blue"> 鍑哄簱 </Tag>;
+          }
+          // No default
+        }
+        return '';
+      }
+    }
+  },
+  {
+    title: '绫诲瀷',
+    field: 'type',
+    width: 100,
+    slots: {
+      default: ({ row }) => {
+        if (!row.type || row.type === '') {
+          return '';
+        }
+        return renderDict(row.type, DictEnum.SPARE_INOUT_TYPE);
+      }
+    }
+  },
+  {
+    title: '鍏ュ簱',
+    field: 'inQuantity',
+    width: 120,
+    slots: {
+      default: ({ row }) => {
+        return row.type && row.type === '1' ? row.quantity : '';
+      }
+    }
+  },
+  {
+    title: '鍑哄簱',
+    field: 'outQuantity',
+    width: 120,
+    slots: {
+      default: ({ row }) => {
+        return row.type && row.type === '2' ? row.quantity : '';
+      }
+    }
+  },
+  {
+    title: '搴撳瓨',
+    field: 'actualStock',
+    width: 80
+  },
+  {
+    title: '鍗曚环',
+    field: 'unitPrice',
+    width: 80
+  },
+  {
+    title: '閲戦',
+    field: 'amount',
+    width: 80
+  }
+];
+
 export const drawerSchema: FormSchemaGetter = () => [
   {
     component: 'Input',
@@ -173,7 +256,7 @@
       show: () => false,
       triggerFields: ['imgUrl']
     },
-    label: '澶囦欢棰勮',
+    label: '澶囦欢棰勮'
   },
   {
     component: 'Input',
diff --git a/eims-ui/apps/web-antd/src/views/eims/spare/index.vue b/eims-ui/apps/web-antd/src/views/eims/spare/index.vue
index 1682ab2..0cb214a 100644
--- a/eims-ui/apps/web-antd/src/views/eims/spare/index.vue
+++ b/eims-ui/apps/web-antd/src/views/eims/spare/index.vue
@@ -10,11 +10,12 @@
 import { Image, Modal, Popconfirm, Space } from 'ant-design-vue';
 
 import { useVbenVxeGrid, vxeCheckboxChecked, type VxeGridProps, vxeSortEvent } from '#/adapter/vxe-table';
-import { delSpare, listSpare, spareExport } from '#/api/eims/spare';
+import { delSpare, listInout, listSpare, spareExport } from '#/api/eims/spare';
 import { configInfoByKey } from '#/api/system/config';
 import { commonDownloadExcel } from '#/utils/file/download';
+import BasisSubTable from '#/views/eims/components/basis-sub-table.vue';
 
-import { columns, querySchema } from './data';
+import { columns, inoutCol, querySchema } from './data';
 import spareDrawer from './spare-drawer.vue';
 import SpareTypeTree from './spare-type-tree.vue';
 
@@ -59,7 +60,7 @@
   height: 'auto',
   keepSource: true,
   pagerConfig: {
-    enabled: false,
+    enabled: false
   },
   proxyConfig: {
     enabled: true,
@@ -84,7 +85,7 @@
     keyField: 'id'
   },
   columnConfig: {
-    resizable: true,
+    resizable: true
   },
   sortConfig: {
     // 杩滅▼鎺掑簭
@@ -94,12 +95,16 @@
   },
   id: 'eims-spare-index'
 };
-
+const id = ref<string>();
 const [BasicTable, tableApi] = useVbenVxeGrid({
   formOptions,
   gridOptions,
   gridEvents: {
-    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams)
+    sortChange: (sortParams) => vxeSortEvent(tableApi, sortParams),
+    cellClick: (e: any) => {
+      const { row } = e;
+      id.value = row.id;
+    }
   }
 });
 
@@ -163,51 +168,56 @@
   <Page :auto-content-height="true">
     <div class="flex h-full gap-[8px]">
       <SpareTypeTree v-model:select-type-id="selectTypeId" class="w-[260px]" @reload="() => tableApi.reload()" @select="() => tableApi.reload()" />
-      <BasicTable class="flex-1 overflow-hidden" table-title="澶囦欢鍙拌处">
-        <template #toolbar-tools>
-          <Space>
-            <a-button v-access:code="['eims:spare:export']" @click="handleDownloadExcel">
-              {{ $t('pages.common.export') }}
-            </a-button>
-            <a-button
-              :disabled="!vxeCheckboxChecked(tableApi)"
-              danger
-              type="primary"
-              v-access:code="['eims:spare:remove']"
-              @click="handleMultiDelete"
-            >
-              {{ $t('pages.common.delete') }}
-            </a-button>
-            <a-button type="primary" v-access:code="['eims:spare:add']" @click="handleAdd">
-              {{ $t('pages.common.add') }}
-            </a-button>
-          </Space>
-        </template>
+      <div class="flex-1 overflow-hidden">
+        <div class="flex h-full gap-[8px] flex-col">
+          <BasicTable class="h-2/3" table-title="澶囦欢鍙拌处">
+            <template #toolbar-tools>
+              <Space>
+                <a-button v-access:code="['eims:spare:export']" @click="handleDownloadExcel">
+                  {{ $t('pages.common.export') }}
+                </a-button>
+                <a-button
+                  :disabled="!vxeCheckboxChecked(tableApi)"
+                  danger
+                  type="primary"
+                  v-access:code="['eims:spare:remove']"
+                  @click="handleMultiDelete"
+                >
+                  {{ $t('pages.common.delete') }}
+                </a-button>
+                <a-button type="primary" v-access:code="['eims:spare:add']" @click="handleAdd">
+                  {{ $t('pages.common.add') }}
+                </a-button>
+              </Space>
+            </template>
 
-        <template #imgUrl="{ row }">
-          <Image v-if="preview && isImageFile(row.imgUrl)" :src="row.imgUrl" height="38px" />
-          <span v-else>{{ row.imgUrl }}</span>
-        </template>
+            <template #imgUrl="{ row }">
+              <Image v-if="preview && isImageFile(row.imgUrl)" :src="row.imgUrl" height="38px" />
+              <span v-else>{{ row.imgUrl }}</span>
+            </template>
 
-        <template #action="{ row }">
-          <Space>
-            <ghost-button v-access:code="['eims:spare:edit']" @click.stop="handleEdit(row)">
-              {{ $t('pages.common.edit') }}
-            </ghost-button>
-            <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
-              <ghost-button danger v-access:code="['eims:spare:remove']" @click.stop="">
-                {{ $t('pages.common.delete') }}
-              </ghost-button>
-            </Popconfirm>
-          </Space>
-        </template>
-      </BasicTable>
+            <template #action="{ row }">
+              <Space>
+                <ghost-button v-access:code="['eims:spare:edit']" @click.stop="handleEdit(row)">
+                  {{ $t('pages.common.edit') }}
+                </ghost-button>
+                <Popconfirm :get-popup-container="getVxePopupContainer" placement="left" title="纭鍒犻櫎锛�" @confirm="handleDelete(row)">
+                  <ghost-button danger v-access:code="['eims:spare:remove']" @click.stop="">
+                    {{ $t('pages.common.delete') }}
+                  </ghost-button>
+                </Popconfirm>
+              </Space>
+            </template>
+          </BasicTable>
+          <BasisSubTable :columns="inoutCol" :list-api="listInout" :req-value="id" class="h-1/3" req-key="id" title="鍑哄叆搴撴槑缁�" />
+        </div>
+      </div>
     </div>
     <SpareDrawer @reload="tableApi.query()" />
   </Page>
 </template>
 
-<style>
+<style lang="scss" scoped>
 /* 缁熶竴鎵�鏈夊垪鐨勮竟妗嗗拰琛岄珮 */
 .vxe-table--body .vxe-body--row .vxe-body--column {
   height: 56px !important;
diff --git a/eims/ruoyi-admin/src/main/resources/application-prod.yml b/eims/ruoyi-admin/src/main/resources/application-prod.yml
index ee68d30..4045cac 100644
--- a/eims/ruoyi-admin/src/main/resources/application-prod.yml
+++ b/eims/ruoyi-admin/src/main/resources/application-prod.yml
@@ -48,9 +48,9 @@
           driverClassName: com.mysql.cj.jdbc.Driver
           # jdbc 鎵�鏈夊弬鏁伴厤缃弬鑰� https://lionli.blog.csdn.net/article/details/122018562
           # rewriteBatchedStatements=true 鎵瑰鐞嗕紭鍖� 澶у箙鎻愬崌鎵归噺鎻掑叆鏇存柊鍒犻櫎鎬ц兘(瀵规暟鎹簱鏈夋�ц兘鎹熻�� 浣跨敤鎵归噺鎿嶄綔搴旇�冭檻鎬ц兘闂)
-          url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+          url: jdbc:mysql://localhost:3306/eims?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
           username: root
-          password: root
+          password: 123456
         # 浠庡簱鏁版嵁婧�
         slave:
           lazy: true
@@ -103,7 +103,7 @@
     # 鏁版嵁搴撶储寮�
     database: 0
     # redis 瀵嗙爜蹇呴』閰嶇疆
-    password: ruoyi123
+    #password: ruoyi123
     # 杩炴帴瓒呮椂鏃堕棿
     timeout: 10s
     # 鏄惁寮�鍚痵sl
diff --git a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
index ea61622..9bbaa6c 100644
--- a/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
+++ b/eims/ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/DictConstants.java
@@ -161,4 +161,16 @@
     }
 
 
+    /**
+     *澶囦欢鍑哄叆搴撶被鍨�
+     */
+    String SPARE_INOUT_TYPE = "spare_inout_type";
+    interface SPARE_INOUT_TYPE_DETAIL {
+        String RK = "1";// 閲囪喘鍏ュ簱
+        String CK = "2"; // 棰嗙敤鍑哄簱
+    }
+
+
+
+
 }

--
Gitblit v1.9.3