zhangcl пре 2 месеци
родитељ
комит
8831074c15

+ 2 - 0
package.json

@@ -64,9 +64,11 @@
     "markmap-view": "^0.16.0",
     "min-dash": "^4.1.1",
     "mitt": "^3.0.1",
+    "moment": "^2.30.1",
     "nprogress": "^0.2.0",
     "pinia": "^2.1.7",
     "pinia-plugin-persistedstate": "^3.2.1",
+    "pinyin": "^4.0.0",
     "qrcode": "^1.5.3",
     "qs": "^6.12.0",
     "sortablejs": "1.15.0",

+ 1 - 0
src/utils/dict.ts

@@ -271,4 +271,5 @@ export enum DICT_TYPE {
   PMS_MAIN_WORK_ORDER_RESULT = 'pms_main_work_order_result', // 保养工单状态
   RQ_IOT_ISCOLLECTION = 'rq_iot_isCollection',//是否数采
   PMS_ORDER_PROCESS_MODE = "pms_main_work_order_process_mode",  // 保养方式 0内部保养  1委外保养
+  PMS_THING_MODEL_UNIT = 'pms_thing_model_unit', // pms属性模板单位
 }

+ 4 - 4
src/views/pms/bom/index.vue

@@ -90,8 +90,8 @@
             </template>
           </el-table-column>
           <el-table-column prop="deviceCategoryName" label="设备分类" />
-          <el-table-column prop="sort" label="排序" />
-          <el-table-column prop="status" label="状态" >
+          <el-table-column prop="sort" label="排序" width="80"/>
+          <el-table-column prop="status" label="状态" width="80">
             <template #default="scope">
               <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
             </template>
@@ -103,8 +103,8 @@
             prop="createTime"
             :formatter="dateFormatter"
           /> -->
-          <el-table-column prop="materials" label="物料数量" />
-          <el-table-column label="操作" align="center" >
+          <el-table-column prop="materials" label="物料数量" width="80"/>
+          <el-table-column label="操作" align="center" width="300">
             <template #default="scope">
               <el-button
                 link

+ 17 - 2
src/views/pms/devicetemplate/DeviceCategoryTree.vue

@@ -6,7 +6,7 @@
       </template>
     </el-input>
   </div>
-  <div class="head-container">
+  <div ref="treeContainer" class="tree-container">
     <el-tree
       ref="treeRef"
       :data="deviceCategoryList"
@@ -19,7 +19,7 @@
       node-key="id"
       @node-click="handleNodeClick"
       @node-contextmenu="handleRightClick"
-      style="height: 35em"
+      style="height: 52em"
     />
   </div>
   <div
@@ -104,6 +104,14 @@ watch(deviceCategoryName, (val) => {
   treeRef.value!.filter(val)
 })
 
+const treeContainer = ref(null)
+const setHeight = () => {
+  if (!treeContainer.value) return
+  const windowHeight = window.innerHeight
+  const containerTop = treeContainer.value.offsetTop
+  treeContainer.value.style.height = `${windowHeight * 0.78}px` // 60px 底部预留
+}
+
 /** 初始化 */
 onMounted(async () => {
   await getTree()
@@ -129,4 +137,11 @@ onMounted(async () => {
 .custom-menu li:hover {
   background: #f5f5f5;
 }
+
+.tree-container {
+  overflow-y: auto;
+  min-width: 100%;
+  border: 1px solid #e4e7ed;
+  border-radius: 4px;
+}
 </style>

+ 77 - 4
src/views/pms/devicetemplate/detail/attrsModel/AttrTemplateModelForm.vue

@@ -9,10 +9,12 @@
       label-width="100px"
     >
       <el-form-item label="属性名称" prop="name">
-        <el-input v-model="formData.name" placeholder="请输入属性名称" />
+        <el-input v-model="formData.name" placeholder="请输入属性名称"
+                  @compositionstart="handleCompositionStart"
+                  @compositionend="handleCompositionEnd"/>
       </el-form-item>
-      <el-form-item label="标识符" prop="code">
-        <el-input v-model="formData.code" placeholder="请输入标识符" />
+      <el-form-item label="标识符" prop="code" >
+        <el-input v-model="formData.code" placeholder="请输入标识符" disabled/>
       </el-form-item>
       <!-- 属性配置 -->
       <DeviceAttrModelProperty
@@ -43,7 +45,8 @@
 import DeviceAttrModelProperty from './AttrTemplateModelProperty.vue'
 import { DeviceAttrModelApi, DeviceAttrModelData } from '@/api/pms/deviceattrmodel'
 import { DataSpecsDataType, DeviceAttrModelFormRules } from './config'
-import { cloneDeep } from 'lodash-es'
+import pinyin from 'pinyin'
+import { cloneDeep, debounce } from 'lodash-es'
 import { isEmpty } from '@/utils/is'
 import { defineProps } from 'vue'
 
@@ -57,11 +60,26 @@ const dialogVisible = ref(false) // 弹窗的是否展示
 const dialogTitle = ref('') // 弹窗的标题
 const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
 const formType = ref('') // 表单的类型:create - 新增;update - 修改
+const isComposing = ref(false)
+
+// 处理输入法开始事件
+const handleCompositionStart = () => {
+  isComposing.value = true
+}
+
+// 处理输入法结束事件
+const handleCompositionEnd = (event: CompositionEvent) => {
+  isComposing.value = false
+  // 手动触发处理
+  generateIdentifier((event.target as HTMLInputElement).value)
+}
+
 const formData = ref<DeviceAttrModelData>({
   deviceCategoryId: -1,
   dataType: DataSpecsDataType.DOUBLE,
   type: DataSpecsDataType.DOUBLE,
   requiredFlag: 0,
+  code: '',
   description: '',
   defaultValue: '',
   selectOptions: {
@@ -151,11 +169,61 @@ const removeDataSpecs = (val: any) => {
   }
 }
 
+// 处理属性名称生成标识符
+const processInputName = (name: string) => {
+  let result = ''
+  for (const char of name) {
+    // 汉字转拼音首字母
+    if (/[\u4e00-\u9fa5]/.test(char)) {
+      const pinyinArray = pinyin(char, {
+        style: pinyin.STYLE_FIRST_LETTER
+      })
+      if (pinyinArray[0]?.[0]) {
+        result += pinyinArray[0][0].toUpperCase()
+      }
+    }
+    // 非汉字字符原样保留
+    else {
+      result += char
+    }
+  }
+  return result
+}
+
+// 中文首字母提取方法
+const getChineseInitials = (name: string) => {
+  const chineseChars = name.match(/[\u4e00-\u9fa5]/g) || []
+  if (chineseChars.length === 0) return ''
+
+  const pinyinArray = pinyin(chineseChars.join(''), {
+    style: pinyin.STYLE_FIRST_LETTER,
+  })
+  return pinyinArray.map(arr => arr[0]?.charAt(0).toUpperCase()).join('')
+}
+
+// 生成标识符方法
+const generateIdentifier = debounce((name: string) => {
+  /* if (formData.value.code)  return */
+
+  const initials = processInputName(name)
+  if (initials) {
+    formData.value.code = `${initials}_${Date.now()}`
+  }
+}, 800)
+
+// 监听属性名称变化
+watchEffect(() => {
+  if (formData.value.name && !isComposing.value) {
+    generateIdentifier(formData.value.name)
+  }
+})
+
 /** 重置表单 */
 const resetForm = () => {
   formData.value = {
     dataType: DataSpecsDataType.DOUBLE,
     type: DataSpecsDataType.DOUBLE,
+    code: '',
     selectOptions: {
       type: DataSpecsDataType.DOUBLE,
       dataSpecs: {
@@ -165,4 +233,9 @@ const resetForm = () => {
   }
   formRef.value?.resetFields()
 }
+
+onMounted(async () => {
+  // 如果不修改 属性名称 不要自动生成新标识符
+  isComposing.value = true
+})
 </script>

+ 1 - 1
src/views/pms/devicetemplate/detail/dataSpecs/DeviceAttrModelNumberDataSpecs.vue

@@ -51,7 +51,7 @@
       @change="unitChange"
     >
       <el-option
-        v-for="(item, index) in getStrDictOptions(DICT_TYPE.IOT_THING_MODEL_UNIT)"
+        v-for="(item, index) in getStrDictOptions(DICT_TYPE.PMS_THING_MODEL_UNIT)"
         :key="index"
         :label="item.label"
         :value="item.label + '-' + item.value"

+ 5 - 5
src/views/pms/iotlockstock/IotAddToStock.vue

@@ -12,7 +12,7 @@
         <el-row>
           <el-col :span="8">
             <el-form-item label="工厂" prop="factoryId">
-              <el-select v-model="formData.factoryId" clearable placeholder="请选择工厂" class="!w-240px" @change="selectedFactoryChange">
+              <el-select v-model="formData.factoryId" clearable placeholder="请选择工厂" class="!w-240px" @change="selectedFactoryChange" disabled>
                 <el-option
                   v-for="item in factoryList"
                   :key="item.id"
@@ -24,7 +24,7 @@
           </el-col>
           <el-col :span="8">
             <el-form-item label="成本中心" prop="costCenterId">
-              <el-select v-model="formData.costCenterId" clearable placeholder="请选择成本中心" class="!w-240px">
+              <el-select v-model="formData.costCenterId" clearable placeholder="请选择成本中心" class="!w-240px" disabled>
                 <el-option
                   v-for="item in costCenterList"
                   :key="item.id"
@@ -170,8 +170,8 @@ const formData = ref({
 })
 
 const formRules = reactive({
-  factoryId: [{ required: true, message: '工厂不能为空', trigger: 'blur' }],
-  costCenterId: [{ required: true, message: '成本中心不能为空', trigger: 'blur' }],
+  // factoryId: [{ required: true, message: '工厂不能为空', trigger: 'blur' }],
+  // costCenterId: [{ required: true, message: '成本中心不能为空', trigger: 'blur' }],
 })
 
 // 多选 物料
@@ -206,7 +206,7 @@ const submitForm = async () => {
     return
   }
   if (formData.value.costCenterId === undefined) {
-    message.error('请选择成本中心')
+    message.error('请维护部门的成本中心')
     return
   }
   if (toRaw(list.value).length == 0) {

+ 2 - 1
src/views/pms/iotlockstock/index.vue

@@ -110,6 +110,7 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <!--
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button
@@ -121,7 +122,7 @@
             编辑
           </el-button>
         </template>
-      </el-table-column>
+      </el-table-column> -->
     </el-table>
     <!-- 分页 -->
     <Pagination

+ 26 - 18
src/views/pms/iotmainworkorder/IotMainWorkOrder.vue

@@ -33,10 +33,18 @@
             -->
           </el-col>
           <el-col :span="8">
+            <el-form-item label="保养费用" prop="cost">
+              <el-input
+                v-model="formData.cost"
+                placeholder="根据物料消耗自动生成"
+                disabled
+              />
+            </el-form-item>
+            <!--
             <el-form-item label="责任人" prop="devicePersons">
               <el-input type="text" v-model="formData.devicePersons"  disabled/>
             </el-form-item>
-            <!--
+
             <el-form-item label="责任人" prop="responsiblePerson">
               <el-select v-model="formData.responsiblePerson" filterable clearable style="width: 100%">
                 <el-option
@@ -71,20 +79,6 @@
               />
             </el-form-item>
           </el-col>
-          <el-col :span="8">
-            <el-form-item label="保养费用" prop="cost">
-              <el-input
-                v-model="formData.cost"
-                placeholder="根据物料消耗自动生成"
-                disabled
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="16">
-            <el-form-item label="备注" prop="remark">
-              <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
-            </el-form-item>
-          </el-col>
           <el-col :span="8">
             <el-form-item label="其他费用" prop="otherCost">
               <el-input
@@ -94,6 +88,11 @@
               />
             </el-form-item>
           </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
+            </el-form-item>
+          </el-col>
         </el-row>
       </div>
     </el-form>
@@ -214,6 +213,12 @@
     <ContentWrap>
       <el-table v-loading="false" :data="materialList" :stripe="true" :show-overflow-tooltip="true" v-if="false">
         <el-table-column label="bom节点" align="center" prop="bomNodeId" />
+        <el-table-column label="工厂id" align="center" prop="factoryId" v-if="false"/>
+        <el-table-column label="工厂名称" align="center" prop="factory" v-if="false"/>
+        <el-table-column label="成本中心id" align="center" prop="costCenterId" v-if="false"/>
+        <el-table-column label="成本中心名称" align="center" prop="costCenter" v-if="false"/>
+        <el-table-column label="库存地点id" align="center" prop="storageLocationId" v-if="false"/>
+        <el-table-column label="库存地点名称" align="center" prop="projectDepartment" v-if="false"/>
         <el-table-column label="物料编码" align="center" prop="materialCode" />
         <el-table-column label="物料名称" align="center" prop="materialName" />
         <el-table-column label="单位" align="center" prop="unit" />
@@ -556,10 +561,13 @@ const selectChoose = (selectedMaterial) => {
 
   // 避免重复添加
   processedMaterials.forEach(newMaterial => {
-    // 检查是否已存在相同 bomNodeId + materialCode 的条目
+    // 检查是否已存在相同 工厂+成本中心+库存地点+bomNodeId + materialCode 的条目
     const isExist = materialList.value.some(item =>
       item.bomNodeId === bomNodeId.value &&
-      item.materialCode === newMaterial.materialCode
+      item.materialCode === newMaterial.materialCode &&
+      item.factoryId === newMaterial.factoryId &&
+      item.costCenterId === newMaterial.costCenterId &&
+      item.storageLocationId === newMaterial.storageLocationId
     );
 
     if (!isExist) {
@@ -878,7 +886,7 @@ onMounted(async () => {
         lastNaturalDate: item.lastNaturalDate ? dayjs(item.lastNaturalDate).format('YYYY-MM-DD') : null
       }))
       // 同时查询所有设备的责任人
-      await getDevicePersons();
+      // await getDevicePersons();
     }
   } catch (error) {
     console.error('数据加载失败:', error)

+ 17 - 17
src/views/pms/iotmainworkorder/IotMainWorkOrderAdd.vue

@@ -31,12 +31,21 @@
               <el-input type="text" v-model="formData.orderNumber" disabled/>
             </el-form-item>
             -->
+
           </el-col>
           <el-col :span="8">
+            <el-form-item label="保养费用" prop="cost">
+              <el-input
+                v-model="formData.cost"
+                placeholder="根据物料消耗自动生成"
+                disabled
+              />
+            </el-form-item>
+            <!--
             <el-form-item label="责任人" prop="devicePersons">
               <el-input type="text" v-model="formData.devicePersons"  disabled/>
             </el-form-item>
-            <!--
+
             <el-form-item label="责任人" prop="responsiblePerson">
               <el-select v-model="formData.responsiblePerson" filterable clearable style="width: 100%" disabled>
                 <el-option
@@ -71,20 +80,6 @@
               />
             </el-form-item>
           </el-col>
-          <el-col :span="8">
-            <el-form-item label="保养费用" prop="cost">
-              <el-input
-                v-model="formData.cost"
-                placeholder="根据物料消耗自动生成"
-                disabled
-              />
-            </el-form-item>
-          </el-col>
-          <el-col :span="16">
-            <el-form-item label="备注" prop="remark">
-              <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
-            </el-form-item>
-          </el-col>
           <el-col :span="8">
             <el-form-item label="其他费用" prop="otherCost">
               <el-input
@@ -94,6 +89,12 @@
               />
             </el-form-item>
           </el-col>
+          <el-col :span="24">
+            <el-form-item label="备注" prop="remark">
+              <el-input v-model="formData.remark" type="textarea" placeholder="请输入备注" />
+            </el-form-item>
+          </el-col>
+
         </el-row>
       </div>
     </el-form>
@@ -613,7 +614,6 @@ const selectChoose = (selectedMaterial) => {
   });
 }
 
-
 const deviceChoose = async(selectedDevices) => {
   const newIds = selectedDevices.map(device => device.id)
   deviceIds.value = [...new Set([...deviceIds.value, ...newIds])]
@@ -669,7 +669,7 @@ const deviceChoose = async(selectedDevices) => {
     }
   })
   // 新增完设备后 查询现有设备-bom明细中 所有设备配置的负责人姓名 逗号分隔
-  await getDevicePersons();
+  // await getDevicePersons();
 }
 
 /** 查看已经选择的物料 并编辑 */

+ 3 - 0
src/views/pms/iotmainworkorder/SelectedMaterialDrawer.vue

@@ -13,6 +13,9 @@
       <div v-loading="loading" style="height: 100%">
         <el-table :data="filteredMaterials" style="width: 100%">
           <el-table-column prop="bomNodeId" label="bom节点" width="180" v-if="false"/>
+          <el-table-column prop="factory" label="工厂" width="180" />
+          <el-table-column prop="costCenter" label="成本中心" width="180" />
+          <el-table-column prop="projectDepartment" label="库存地点" width="180" />
           <el-table-column prop="materialName" label="物料名称" width="180" />
           <el-table-column prop="materialCode" label="物料编码" width="180" />
           <el-table-column prop="unit" label="单位" width="180" />

+ 14 - 1
src/views/pms/iotmainworkorder/WorkOrderMaterial.vue

@@ -124,7 +124,7 @@
             <el-input
               v-model="scope.row.quantity"
               @click.stop=""
-              @focus="scope.$el.querySelector('input').focus()"
+              @focus="handleInputFocus(scope.row)"
             />
           </template>
         </el-table-column>
@@ -330,6 +330,19 @@ const toggleRow = (row) => {
   }
 }
 
+// 处理输入框焦点事件(自动选中当前行)
+const handleInputFocus = (row: WorkOrderBomMaterialApi.IotMainWorkOrderBomMaterialVO) => {
+  const getRowUniqueKey = (row) => {
+    return `${row.factoryId}_${row.costCenterId}_${row.storageLocationId}_${row.materialCode}`
+  }
+  const currentKey = getRowUniqueKey(row)
+  // 如果未选中则添加到选中列表
+  const exists = selectedRows.value.some(item => getRowUniqueKey(item) === currentKey)
+  if (!exists) {
+    selectedRows.value.push(row)
+  }
+}
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1

+ 10 - 22
src/views/pms/iotmainworkorder/index.vue

@@ -25,7 +25,7 @@
           class="!w-240px"
         >
           <el-option
-            v-for="dict in getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT)"
+            v-for="dict in resultOptions"
             :key="dict.value"
             :label="dict.label"
             :value="dict.value"
@@ -90,27 +90,6 @@
         </template>
       </el-table-column>
       <el-table-column label="负责人" align="center" prop="responsiblePersonName" />
-      <el-table-column
-        label="实际保养开始时间"
-        align="center"
-        prop="actualStartTime"
-        :formatter="dateFormatter"
-        width="180px"
-      />
-      <el-table-column
-        label="实际保养结束时间"
-        align="center"
-        prop="actualEndTime"
-        :formatter="dateFormatter"
-        width="180px"
-      />
-      <el-table-column
-        label="创建时间"
-        align="center"
-        prop="createTime"
-        :formatter="dateFormatter"
-        width="180px"
-      />
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button
@@ -224,6 +203,15 @@ const resetQuery = () => {
   handleQuery()
 }
 
+// 保养状态 下拉列表 添加数据字典外的选项
+const resultOptions = computed(() => [
+  {
+    label: '全部',
+    value: '0' // 空值会触发 clearable 效果
+  },
+  ...getStrDictOptions(DICT_TYPE.PMS_MAIN_WORK_ORDER_RESULT)
+])
+
 /** 添加/修改操作 */
 const formRef = ref()
 const openForm = (type: string, id?: number) => {

+ 0 - 2
src/views/pms/iotsapstock/IotConfigSafeStock.vue

@@ -51,8 +51,6 @@
         </el-table-column>
       </el-table>
     </ContentWrap>
-    <!--
-    <MaterialSelect ref="materialFormRef" @choose="materialChoose" /> -->
     <SelectSapStock ref="sapStockFormRef" @choose="stockChoose" />
   </ContentWrap>
   <ContentWrap>

+ 2 - 11
src/views/pms/iotsapstock/IotSapStockConfig.vue

@@ -99,6 +99,7 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <!--
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button
@@ -110,18 +111,8 @@
           >
             安全库存
           </el-button>
-          <!--
-          <el-button
-            link
-            type="danger"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['pms:iot-sap-stock:delete']"
-          >
-            删除
-          </el-button>
-          -->
         </template>
-      </el-table-column>
+      </el-table-column> -->
     </el-table>
     <!-- 分页 -->
     <Pagination

+ 10 - 1
src/views/pms/iotsapstock/SelectSapStock.vue

@@ -75,7 +75,7 @@
               <el-input
                 v-model="scope.row.safetyStock"
                 @click.stop=""
-                @focus="scope.$el.querySelector('input').focus()"
+                @focus="handleInputFocus(scope.row)"
               />
             </template>
           </el-table-column>
@@ -186,6 +186,15 @@ const getList = async () => {
   }
 }
 
+// 处理输入框焦点事件(自动选中当前行)
+const handleInputFocus = (row: MaterialApi.MaterialVO) => {
+  // 如果未选中则添加到选中列表
+  const exists = selectedRows.value.some(item => item.id === row.id)
+  if (!exists) {
+    selectedRows.value.push(row)
+  }
+}
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNo = 1

+ 34 - 11
src/views/pms/iotsapstock/index.vue

@@ -57,6 +57,21 @@
           class="!w-220px"
         />
       </el-form-item>
+      <el-form-item label="是否配置安全库存" prop="configFlag" label-width="140px">
+        <el-select
+          v-model="queryParams.configFlag"
+          placeholder="请选择"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="dict in resultOptions"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
         <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
@@ -99,6 +114,7 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <!--
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button
@@ -110,18 +126,8 @@
           >
             安全库存
           </el-button>
-          <!--
-          <el-button
-            link
-            type="danger"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['pms:iot-sap-stock:delete']"
-          >
-            删除
-          </el-button>
-          -->
         </template>
-      </el-table-column>
+      </el-table-column> -->
     </el-table>
     <!-- 分页 -->
     <Pagination
@@ -180,6 +186,7 @@ const queryParams = reactive({
   sort: undefined,
   status: undefined,
   remark: undefined,
+  configFlag: 'A',
   createTime: [],
 })
 const queryFormRef = ref() // 搜索的表单
@@ -240,6 +247,22 @@ const selectedFactoryChange = async (selectedId: number | undefined) => {
   storageLocationList.value = await SapOrgApi.SapOrgApi.getSelectedList(selectedFactoryReqVO.value)
 }
 
+// 是否已经配置了安全库存 下拉列表 模拟字典项
+const resultOptions = computed(() => [
+  {
+    label: '全部',
+    value: 'A' // 空值会触发 clearable 效果
+  },
+  {
+    label: '是',
+    value: 'Y' // 空值会触发 clearable 效果
+  },
+  {
+    label: '否',
+    value: 'N' // 空值会触发 clearable 效果
+  },
+])
+
 /** 删除按钮操作 */
 const handleDelete = async (id: number) => {
   try {