Browse Source

feat: ✨ 完成入库,修复登录bug

@sun-chaoqun 2 năm trước cách đây
mục cha
commit
c9fe3812fc

+ 1 - 0
.gitignore

@@ -9,6 +9,7 @@ lerna-debug.log*
 
 node_modules
 dist
+ERP
 dist-ssr
 *.local
 

+ 2 - 2
src/api/index.ts

@@ -12,7 +12,7 @@ let loadingInstance: LoadingType = {}
 
 const config = {
   // 默认地址请求地址,可在 .env.*** 文件中修改
-  baseURL: import.meta.env.VITE_BZD_ERP_APP_API as string,
+  // baseURL: import.meta.env.VITE_BZD_ERP_APP_API as string,
   // 设置超时时间(10s)
   timeout: ResultEnum.TIMEOUT as number,
   // 跨域时候允许携带凭证
@@ -63,7 +63,6 @@ class RequestHttp {
         loadingInstance.close && loadingInstance.close()
         // 无权限访问 || 登录密码错误(code == 202)
         // if (data.Code === ResultEnum.ROLE) {
-        //   // router.replace('/404')
         //   return Promise.reject(data)
         // }
         // * 登陆失效(code == 201)
@@ -88,6 +87,7 @@ class RequestHttp {
       },
       async (error: AxiosError) => {
         loadingInstance.close && loadingInstance.close()
+
         // 请求超时 && 网络错误单独判断,没有 response
         if (error.message.indexOf('timeout') !== -1) ElMessage.error('请求超时!请您稍后重试')
         if (error.message.indexOf('Network Error') !== -1) ElMessage.error('网络错误!请您稍后重试')

+ 96 - 96
src/router/modules/staticRouter.ts

@@ -13,102 +13,102 @@ export const staticRouter: RouteRecordRaw[] = [
       title: '起始页'
     },
     children: [
-      // {
-      //   path: '/list',
-      //   name: 'List',
-      //   component: () => import('@/views/storehouse/List.vue'),
-      //   meta: {
-      //     title: '仓库列表'
-      //   }
-      // },
-      // {
-      //   path: '/classify',
-      //   name: 'Classify',
-      //   component: () => import('@/views/storehouse/Classify.vue'),
-      //   meta: {
-      //     title: '产品分类'
-      //   }
-      // },
-      // {
-      //   path: '/productionList',
-      //   name: 'ProductionList',
-      //   component: () => import('@/views/storehouse/ProductionList.vue'),
-      //   meta: {
-      //     title: '产品列表'
-      //   }
-      // },
-      // {
-      //   path: '/ioTNetworkCard',
-      //   name: 'IoTNetworkCard',
-      //   component: () => import('@/views/storehouse/IoTNetworkCard.vue'),
-      //   meta: {
-      //     title: '物联网卡'
-      //   }
-      // },
-      // {
-      //   path: '/saleMange',
-      //   name: 'SaleMange',
-      //   component: () => import('@/views/storehouse/sales/index.vue'),
-      //   // redirect: '/contract',
-      //   meta: {
-      //     routerView: true,
-      //     title: '销售管理'
-      //   },
-      //   children: [
-      //     {
-      //       path: '/contract',
-      //       name: 'Contract',
-      //       component: () => import('@/views/storehouse/sales/Contract.vue'),
-      //       meta: {
-      //         title: '合同管理'
-      //       }
-      //     },
-      //     {
-      //       path: '/contractDetail/:id',
-      //       name: 'ContractDetail',
-      //       component: () => import('@/views/storehouse/sales/ContractDetail.vue'),
-      //       meta: {
-      //         title: '合同详情'
-      //       }
-      //     },
-      //     {
-      //       path: '/contractSale',
-      //       name: 'ContractSale',
-      //       component: () => import('@/views/storehouse/sales/ContractSale.vue'),
-      //       meta: {
-      //         title: '合同详情(销售)'
-      //       }
-      //     }
-      //   ]
-      // },
-      // {
-      //   path: '/inventoryMange',
-      //   name: 'InventoryMange',
-      //   component: () => import('@/views/storehouse/inventory/index.vue'),
-      //   // redirect: '/contract',
-      //   meta: {
-      //     routerView: true,
-      //     title: '库存管理'
-      //   },
-      //   children: [
-      //     {
-      //       path: '/device',
-      //       name: 'Device',
-      //       component: () => import('@/views/storehouse/inventory/Device.vue'),
-      //       meta: {
-      //         title: '设备列表'
-      //       }
-      //     },
-      //     {
-      //       path: '/inStorage',
-      //       name: 'InStorage',
-      //       component: () => import('@/views/storehouse/inventory/InStorage.vue'),
-      //       meta: {
-      //         title: '入库管理'
-      //       }
-      //     }
-      //   ]
-      // },
+      {
+        path: '/list',
+        name: 'List',
+        component: () => import('@/views/storehouse/List.vue'),
+        meta: {
+          title: '仓库列表'
+        }
+      },
+      {
+        path: '/classify',
+        name: 'Classify',
+        component: () => import('@/views/storehouse/Classify.vue'),
+        meta: {
+          title: '产品分类'
+        }
+      },
+      {
+        path: '/productionList',
+        name: 'ProductionList',
+        component: () => import('@/views/storehouse/ProductionList.vue'),
+        meta: {
+          title: '产品列表'
+        }
+      },
+      {
+        path: '/ioTNetworkCard',
+        name: 'IoTNetworkCard',
+        component: () => import('@/views/storehouse/IoTNetworkCard.vue'),
+        meta: {
+          title: '物联网卡'
+        }
+      },
+      {
+        path: '/saleMange',
+        name: 'SaleMange',
+        component: () => import('@/views/storehouse/sales/index.vue'),
+        // redirect: '/contract',
+        meta: {
+          routerView: true,
+          title: '销售管理'
+        },
+        children: [
+          {
+            path: '/contract',
+            name: 'Contract',
+            component: () => import('@/views/storehouse/sales/Contract.vue'),
+            meta: {
+              title: '合同管理'
+            }
+          },
+          {
+            path: '/contractDetail/:id',
+            name: 'ContractDetail',
+            component: () => import('@/views/storehouse/sales/ContractDetail.vue'),
+            meta: {
+              title: '合同详情'
+            }
+          },
+          {
+            path: '/contractSale',
+            name: 'ContractSale',
+            component: () => import('@/views/storehouse/sales/ContractSale.vue'),
+            meta: {
+              title: '合同详情(销售)'
+            }
+          }
+        ]
+      },
+      {
+        path: '/inventoryMange',
+        name: 'InventoryMange',
+        component: () => import('@/views/storehouse/inventory/index.vue'),
+        // redirect: '/contract',
+        meta: {
+          routerView: true,
+          title: '库存管理'
+        },
+        children: [
+          {
+            path: '/device',
+            name: 'Device',
+            component: () => import('@/views/storehouse/inventory/Device.vue'),
+            meta: {
+              title: '设备列表'
+            }
+          },
+          {
+            path: '/inStorage',
+            name: 'InStorage',
+            component: () => import('@/views/storehouse/inventory/InStorage.vue'),
+            meta: {
+              title: '入库管理'
+            }
+          }
+        ]
+      },
       // {
       //   path: '/contract',
       //   name: 'Contract',

+ 3 - 3
src/stores/index.ts

@@ -12,10 +12,10 @@ export const GlobalStore = defineStore({
     loading: false,
     isCollapse: false,
     breadcrumb: [],
-    userInfo: JSON.parse(localStorage.getItem('User_info') as any) || {},
+    userInfo: JSON.parse(sessionStorage.getItem('User_info') as any) || {},
     UserDeptList: [],
     UserPostList: [],
-    User_tokey: localStorage.getItem('User_tokey') || '',
+    User_tokey: sessionStorage.getItem('User_tokey') || '',
     path: '',
     MenuList: [], // 保存原始菜单
     allBreadcrumbList: [], // 用作面包屑
@@ -65,7 +65,7 @@ export const GlobalStore = defineStore({
       const res: any = await User_Info({ User_tokey: this.GET_User_tokey })
       if (res.Code === 200) {
         this.SET_User_Info(res.Data)
-        localStorage.setItem('User_info', JSON.stringify(res.Data))
+        sessionStorage.setItem('User_info', JSON.stringify(res.Data))
       }
     },
     async SET_Menu_User_List() {

+ 4 - 0
src/styles/element.scss

@@ -27,6 +27,10 @@
   }
 }
 
+img {
+  border-radius: 8px;
+}
+
 .el-table .cell {
   white-space: nowrap !important;
 }

+ 4 - 4
src/utils/common.ts

@@ -120,16 +120,16 @@ export const getFormatDuration = (time: number) => {
   let hour = 0
   let minute = 0
   let result = ''
-  if (time >= 60) {
+  if (time >= 60 || time < 0) {
     hour = time / 60
     minute = time % 60
   } else {
-    result = '' + time + ''
+    result = '' + time + '小时'
   }
-  if (minute > 0) {
+  if (Math.abs(minute) > 0) {
     result = '' + parseInt(minute + '') + '分' + result
   }
-  if (hour > 0) {
+  if (Math.abs(hour) > 0) {
     result = '' + parseInt(hour + '') + '小时' + result
   }
   return result

+ 21 - 13
src/views/Login.vue

@@ -35,21 +35,29 @@ const submitForm = (formEl: FormInstance | undefined) => {
   if (!formEl) return
   formEl.validate(async valid => {
     if (valid) {
-      loading.value = true
-      let res: any = {}
-      res = await Login_verification({ bzd_username: ruleForm.username, bzd_password: fnMd5(ruleForm.password) })
-      if (res.Code === 200) {
-        localStorage.setItem('User_tokey', res.Data)
-        globalStore.SET_User_Tokey(res.Data)
-        router.replace('/')
-        ElNotification.success({
-          title: '登录成功',
-          message: '欢迎进入宝智达ERP系统!',
-          position: 'bottom-right'
+      try {
+        loading.value = true
+        const res: any = await Login_verification({
+          bzd_username: ruleForm.username,
+          bzd_password: fnMd5(ruleForm.password)
         })
-        setTimeout(() => {
+        if (res.Code === 200) {
+          sessionStorage.setItem('User_tokey', res.Data)
+          globalStore.SET_User_Tokey(res.Data)
+          router.replace('/')
+          ElNotification.success({
+            title: '登录成功',
+            message: '欢迎进入宝智达ERP系统!',
+            position: 'bottom-right'
+          })
+          setTimeout(() => {
+            loading.value = false
+          }, 1000)
+        }
+      } catch (error: any) {
+        if (error.Code === 202) {
           loading.value = false
-        }, 1000)
+        }
       }
     } else {
       return false

+ 104 - 142
src/views/storehouse/inventory/InStorageForm.vue

@@ -5,6 +5,7 @@ import { Delete, CirclePlus } from '@element-plus/icons-vue'
 import { GlobalStore } from '@/stores/index'
 import { ElMessage } from 'element-plus'
 import {
+  Storehouse_StockIn_Add,
   Storehouse_Product_List,
   Storehouse_ProductClass_List,
   Storehouse_Product_Model_List,
@@ -13,16 +14,16 @@ import {
 } from '@/api/storehouse/index'
 import type { FormInstance, FormRules } from 'element-plus'
 import { default as vElTableInfiniteScroll } from 'el-table-infinite-scroll'
+import InStorageSn from './InStorageSn.vue'
 
 const isNew = ref(true)
 const selectTable = ref()
-const snTable = ref()
 let selectProductData: any[] = []
 const globalStore = GlobalStore()
 const formLabelWidth = ref('120px')
 const ruleFormRef = ref<FormInstance>()
 const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
-const drawerSnRef = ref<InstanceType<typeof Drawer> | null>(null)
+const drawerSnRef = ref<InstanceType<typeof InStorageSn> | null>(null)
 const drawerProductRef = ref<InstanceType<typeof Drawer> | null>(null)
 
 const classOptions = ref<any[]>([])
@@ -50,8 +51,19 @@ const form = reactive<FormType>({
   T_date: '',
   T_remark: ''
 })
+
+const validate_T_product = (rule: any, value: any, callback: any) => {
+  if (value.includes(undefined) || value === '') {
+    callback(new Error('请填写产品数量'))
+  } else if (value.includes(null)) {
+    callback(new Error('请添加产品SN'))
+  } else {
+    callback()
+  }
+}
+
 const rules = reactive<FormRules>({
-  // T_product: [{ validator: validate_T_product, trigger: 'blur' }],
+  T_product: [{ validator: validate_T_product, trigger: 'blur' }],
   T_depot_id: [{ required: true, message: '请选择仓库', trigger: 'blur' }],
   T_date: [{ required: true, message: '请选择入库日期', trigger: 'blur' }]
 })
@@ -62,7 +74,7 @@ const columns = [
   { label: '产品图片', prop: 'T_img', align: 'center ', name: 'T_img' },
   { label: '产品名称', prop: 'T_name', align: 'center ' },
   { label: '产品分类', prop: 'T_class_name', align: 'center ' },
-  { label: '产品型号', prop: 'T_model', align: 'center ' },
+  { label: '产品型号', prop: 'T_model', align: 'center ', ellipsis: true },
   { label: '产品规格', prop: 'T_spec', align: 'center ' },
   { label: '是否关联SN', prop: 'T_relation_sn', align: 'center ', width: 120, name: 'T_relation_sn' },
   { label: '*数量', prop: 'count', align: 'center ', name: 'count' },
@@ -87,18 +99,67 @@ const countBlurHandle = () => {
     return `${item.Id},${item.count}`
   })
 }
-// const snBlurHandle = ()=>{
-//   form.T_product = tableData.value.map(item => {
-//     if (!item.sn) return undefined
-//     return `${item.Id},${item.count}`
-//   })
-// }
+const getDeviceSnToProduct = () => {
+  const DeviceSnData: any = drawerSnRef.value?.getDeviceSn()
+  // if (!DeviceSnData.size) {
+  //   const index = tableData.value.findIndex((item: any) => item.T_relation_sn === 1)
+  //   if (index !== -1) return [null]
+  //   else {
+  //     return tableData.value.map(item => {
+  //       if (!item.count) return undefined
+  //       return `${item.Id},${item.count}`
+  //     })
+  //   }
+  // }
+  if (!DeviceSnData.size) return [null]
+  if (!tableData.value.every((item: any) => item.count)) return [undefined]
+  return tableData.value.map((item: any) => {
+    let product: any = ''
+    DeviceSnData?.forEach((value: any, key: number) => {
+      // T_relation_sn === 1
+      if (item.Id === key) {
+        if (item.T_relation_sn === 1 && value.length > 0) {
+          let str = ''
+          value.forEach((snObj: any) => (str += snObj.sn + ','))
+          product = `${item.Id}-${item.count}-${str}`
+        } else {
+          product = null
+        }
+      } else {
+        if (item.count) {
+          product = `${item.Id}-${item.count}-`
+        } else {
+          product = undefined
+        }
+      }
+    })
+    return product + '|'
+  })
+}
+
+const AddInStorage = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  form.T_product = getDeviceSnToProduct()
+
+  formEl.validate(async valid => {
+    if (valid) {
+      const res = await Storehouse_StockIn_Add({
+        User_tokey: globalStore.GET_User_tokey,
+        ...form,
+        T_product: form.T_product.toString()
+      })
+      console.log(res)
+    }
+  })
+}
 
 const deleteProduct = (row: any) => {
   tableData.value = tableData.value.filter(item => item.Id !== row.Id)
 
   // 设置产品的选中
   selectTable.value?.toggleRowSelection(row, false)
+  // 删除设备得sn
+  drawerSnRef.value?.deleteDeviceSn(row.Id)
 }
 
 const callbackDrawer = (done: Fn) => {
@@ -107,7 +168,6 @@ const callbackDrawer = (done: Fn) => {
   done()
 }
 const callbackProductDrawer = (done: Fn) => done()
-const callbackSnDrawer = (done: Fn) => done()
 
 const resetForm = (formEl: FormInstance | undefined) => {
   if (!formEl) return
@@ -207,6 +267,7 @@ let total = 0
 const tableProductData = ref<any[]>([])
 const getProductList = async () => {
   const res: any = await Storehouse_Product_List({ ...initParam, T_name: autoSelect.value })
+  if (!res.Data.Data) return
   tableProductData.value.push(...res.Data.Data)
   total = res.Data.Num
   if (!isNew.value) {
@@ -220,15 +281,8 @@ const getProductList = async () => {
 }
 const ProductselectionChange = (row: any[]) => {
   const newProduct = row.find((product: any) => tableData.value.findIndex((item: any) => item.Id === product.Id) === -1)
+
   newProduct && tableData.value.push(newProduct)
-  // if (!isNew.value) {
-  //   const newProduct = row.find(
-  //     (product: any) => tableData.value.findIndex((item: any) => item.Id === product.Id) === -1
-  //   )
-  //   newProduct && tableData.value.push({ ...newProduct })
-  // } else {
-  //   tableData.value = row
-  // }
 }
 
 // 搜索模型
@@ -244,40 +298,16 @@ const getRowKey = (row: any) => {
 }
 
 // 添加sn
-const addDeviceSn = () => {
-  //
-  drawerSnRef.value?.openDrawer()
+const addDeviceSn = (id: number) => {
+  drawerSnRef.value?.addDeviceSn(id)
 }
-const tableSnData: any[] = reactive([{ sn: 12131423 }])
-const snColumns = [
-  { type: 'index', label: '序号', width: 80, align: 'center ' },
-  { label: 'SN', prop: 'sn', align: 'center ' },
-  { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
-]
-
-const ruleSnFormRef = ref()
-const formSn = reactive({
-  T_sn: ''
-})
-const rulesSn = reactive<FormRules>({
-  T_sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
-})
-
-const addSn = (formEl: FormInstance | undefined) => {
-  if (!formEl) return
-  formEl.validate(async valid => {
-    if (valid) {
-      console.log('push')
-
-      tableSnData.push({ sn: formSn.T_sn })
+const autoGetCount = (length: number, id: number) => {
+  tableData.value.forEach((item: any) => {
+    if (item.Id === id) {
+      item.count = length
     }
   })
 }
-const deleteSn = (row: any) => {
-  const index = tableSnData.findIndex((item: any) => row.sn === item.sn)
-  tableSnData.splice(index, 1)
-}
-
 // 接受props
 interface ItemType {
   T_name: string
@@ -302,7 +332,7 @@ defineExpose({
       <el-form ref="ruleFormRef" :model="form" :rules="rules">
         <el-divider border-style="dashed" />
         <el-form-item label="入库单号:" :label-width="formLabelWidth" prop="T_number">
-          <el-input v-model="form.T_number" type="text" :disabled="true" placeholder="请输入入库单号" class="w-50" />
+          <el-input v-model="form.T_number" type="text" :disabled="true" placeholder="系统自动生成" class="w-50" />
         </el-form-item>
         <el-form-item label="入库仓库:" :label-width="formLabelWidth" prop="T_depot_id">
           <el-select v-model="form.T_depot_id" class="w-50" clearable placeholder="请选择入库仓库~">
@@ -332,27 +362,30 @@ defineExpose({
             }"
           >
             <template v-for="item in columns" :key="item.prop">
-              <el-table-column v-bind="item" v-if="item.fixed !== 'right'">
+              <el-table-column v-bind="item" v-if="item.fixed !== 'right' && !item.ellipsis">
                 <template #header v-if="item.prop === 'count' || item.prop === 'sn'">
                   <span style="color: red">{{ item.label }}</span>
                 </template>
                 <template #default="{ row }" v-if="item.prop === item.name">
                   <el-input
-                    v-if="item.prop === 'count'"
+                    v-if="item.prop === 'count' && row.T_relation_sn !== 1"
                     v-model.number="row.count"
                     type="text"
                     autocomplete="off"
                     @blur="countBlurHandle"
                   />
-                  <el-button
-                    v-if="item.prop === 'sn'"
-                    link
-                    type="primary"
-                    size="small"
-                    :icon="CirclePlus"
-                    @click="addDeviceSn"
-                    >添加</el-button
-                  >
+                  <div v-if="item.prop === 'sn'">
+                    <el-button
+                      v-if="row.T_relation_sn === 1"
+                      link
+                      type="primary"
+                      size="small"
+                      :icon="CirclePlus"
+                      @click="addDeviceSn(row.Id)"
+                      >添加</el-button
+                    >
+                    <span v-else>-</span>
+                  </div>
                   <span v-if="item.prop === 'T_relation_sn'">
                     <el-tag v-if="row.T_relation_sn === 1" effect="dark">是</el-tag>
                     <el-tag v-else type="success" effect="dark">否</el-tag>
@@ -360,6 +393,13 @@ defineExpose({
                   <el-image v-if="item.prop === 'T_img'" style="height: 50px" :src="row.T_img" fit="cover" />
                 </template>
               </el-table-column>
+              <el-table-column v-if="item.ellipsis && item.prop === 'T_model'" v-bind="item">
+                <template #default="{ row }">
+                  <el-tooltip effect="dark" :content="row.T_model" placement="bottom">
+                    {{ row.T_model }}
+                  </el-tooltip>
+                </template>
+              </el-table-column>
               <el-table-column v-bind="item" v-if="item.fixed === 'right'">
                 <template #default="{ row }">
                   <el-button link type="danger" size="small" :icon="Delete" @click="deleteProduct(row)">删除</el-button>
@@ -375,7 +415,6 @@ defineExpose({
         </el-form-item>
         <el-form-item label="入库仓库:" :label-width="formLabelWidth" prop="T_number">
           <el-input
-            class="w-50"
             v-model="form.T_remark"
             :autosize="{ minRows: 4, maxRows: 6 }"
             type="textarea"
@@ -385,7 +424,7 @@ defineExpose({
         <div class="btn">
           <el-divider>
             <el-button>取消</el-button>
-            <el-button v-if="isNew" color="#626aef">提交</el-button>
+            <el-button v-if="isNew" color="#626aef" @click="AddInStorage(ruleFormRef)">提交</el-button>
           </el-divider>
         </div>
         <Drawer ref="drawerProductRef" :handleClose="callbackProductDrawer" size="70%">
@@ -477,88 +516,11 @@ defineExpose({
             </el-table>
           </el-card>
         </Drawer>
-        <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
-          <el-card class="box-card" shadow="never">
-            <template #header>
-              <div class="sn-header">
-                <el-form ref="ruleSnFormRef" :model="formSn" :rules="rulesSn">
-                  <el-form-item label="SN:" :label-width="formLabelWidth" prop="T_sn">
-                    <el-input v-model="formSn.T_sn" type="text" placeholder="请输入SN" class="w-50" />
-                  </el-form-item>
-                </el-form>
-                <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
-              </div>
-            </template>
-            <el-table
-              ref="snTable"
-              :data="tableSnData"
-              style="width: 100%; height: 99%"
-              :header-cell-style="{
-                background: '#dedfe0',
-                height: '50px'
-              }"
-            >
-              <template v-for="item in snColumns" :key="item">
-                <el-table-column v-if="item.type === 'index'" v-bind="item" />
-                <el-table-column v-if="item.prop" align="center" v-bind="item">
-                  <template #default="{ row }">
-                    <el-button
-                      v-if="item.prop === 'operation'"
-                      link
-                      type="danger"
-                      size="small"
-                      :icon="Delete"
-                      @click="deleteSn(row)"
-                      >删除</el-button
-                    >
-                  </template>
-                </el-table-column>
-              </template>
-            </el-table>
-          </el-card>
-        </Drawer>
+        <InStorageSn ref="drawerSnRef" @onCount="autoGetCount" />
       </el-form>
     </Drawer>
   </div>
 </template>
 <style scoped lang="scss">
-.tooltip-content {
-  max-width: 500px;
-  overflow-y: auto;
-}
-.inStorage-form {
-  :deep(.el-drawer__header) {
-    margin-bottom: 0;
-  }
-  .box-card {
-    height: 100%;
-    :deep(.el-card__body) {
-      height: calc(100% - 70px);
-    }
-    .sn-header {
-      display: flex;
-      justify-content: end;
-    }
-  }
-  .btn {
-    margin-top: 32px;
-    display: flex;
-    justify-content: center;
-    .el-button {
-      padding: 0 32px;
-    }
-  }
-  .w-50 {
-    width: 21.5rem;
-  }
-  .input-suffix {
-    width: 100%;
-    .inline-flex {
-      white-space: nowrap;
-    }
-    .d-flex {
-      display: flex;
-    }
-  }
-}
+@import './index.scss';
 </style>

+ 2 - 2
src/views/storehouse/inventory/InStorageProduct.vue

@@ -137,9 +137,9 @@ const openDrawer = () => {
 
 const selectTableChange = (row: any) => {
   console.log(row, tableData)
-  selectTable.value?.clearSelection()
+  // selectTable.value?.clearSelection()
   nextTick(() => {
-    // selectTable.value?.toggleRowSelection(row, false)
+    selectTable.value?.toggleRowSelection(row, false)
   })
 }
 

+ 131 - 3
src/views/storehouse/inventory/InStorageSn.vue

@@ -1,7 +1,135 @@
-<script setup lang="ts"></script>
+<script setup lang="ts">
+import { ref, reactive, nextTick } from 'vue'
+import Drawer from '@/components/Drawer/index.vue'
+import type { FormInstance, FormRules } from 'element-plus'
+import { Delete } from '@element-plus/icons-vue'
+
+type Fn = () => void
+interface FormSnType {
+  Id: number | undefined
+  T_sn: string
+}
+interface SNType {
+  sn: string
+}
+const snTable = ref()
+const SNDataMap = new Map<number, SNType[]>()
+const tableSnData = ref<any[]>([])
+const ruleSnFormRef = ref<FormInstance>()
+const drawerSnRef = ref<InstanceType<typeof Drawer> | null>(null)
+
+const snColumns = [
+  { type: 'index', label: '序号', width: 80, align: 'center ' },
+  { label: 'SN', prop: 'sn', align: 'center ' },
+  { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
+]
+const formSn = reactive<FormSnType>({
+  Id: undefined,
+  T_sn: ''
+})
+const rulesSn = reactive<FormRules>({
+  T_sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
+})
+
+const addSn = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.validate(async valid => {
+    if (valid) {
+      tableSnData.value.push({ sn: formSn.T_sn })
+      nextTick(() => {
+        resetSnForm(ruleSnFormRef.value)
+      })
+    }
+  })
+}
+const deleteSn = (row: any) => {
+  const index = tableSnData.value.findIndex((item: any) => row.sn === item.sn)
+  tableSnData.value.splice(index, 1)
+}
+
+const callbackSnDrawer = (done: Fn) => {
+  SNDataMap.set(formSn.Id as number, tableSnData.value)
+  emit('onCount', SNDataMap.get(formSn.Id as number)?.length, formSn.Id as number)
+  done()
+  nextTick(() => {
+    resetSnForm(ruleSnFormRef.value)
+    tableSnData.value = []
+  })
+}
+
+const emit = defineEmits<{ (event: 'onCount', value: any, id: number): void }>()
+
+const resetSnForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+}
+
+const addDeviceSn = (id: number) => {
+  formSn.Id = id
+  SNDataMap.set(id, [])
+  drawerSnRef.value?.openDrawer()
+}
+const deleteDeviceSn = (id: number) => SNDataMap.delete(id)
+const getDeviceSn = () => SNDataMap
+defineExpose({
+  getDeviceSn,
+  addDeviceSn,
+  deleteDeviceSn
+})
+</script>
 
 <template>
-  <div></div>
+  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
+    <el-card class="box-card" shadow="never">
+      <template #header>
+        <div class="sn-header">
+          <el-form ref="ruleSnFormRef" :model="formSn" :rules="rulesSn">
+            <el-form-item label="SN:" label-width="120px" prop="T_sn">
+              <el-input v-model="formSn.T_sn" type="text" placeholder="请输入SN" class="w-50" />
+            </el-form-item>
+          </el-form>
+          <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
+        </div>
+      </template>
+      <el-table
+        ref="snTable"
+        :data="tableSnData"
+        style="width: 100%; height: 99%"
+        :header-cell-style="{
+          background: '#dedfe0',
+          height: '50px'
+        }"
+      >
+        <template v-for="item in snColumns" :key="item">
+          <el-table-column v-if="item.type === 'index'" v-bind="item" />
+          <el-table-column v-if="item.prop" align="center" v-bind="item">
+            <template #default="{ row }">
+              <el-button
+                v-if="item.prop === 'operation'"
+                link
+                type="danger"
+                size="small"
+                :icon="Delete"
+                @click="deleteSn(row)"
+                >删除</el-button
+              >
+            </template>
+          </el-table-column>
+        </template>
+      </el-table>
+    </el-card>
+  </Drawer>
 </template>
 
-<style scoped></style>
+<style scoped lang="scss">
+.box-card {
+  height: 100%;
+  :deep(.el-card__body) {
+    height: calc(100% - 70px);
+  }
+  .sn-header {
+    display: flex;
+    justify-content: end;
+  }
+}
+</style>

+ 35 - 0
src/views/storehouse/inventory/index.scss

@@ -0,0 +1,35 @@
+.tooltip-content {
+  max-width: 500px;
+  overflow-y: auto;
+}
+.inStorage-form {
+  :deep(.el-drawer__header) {
+    margin-bottom: 0;
+  }
+  .box-card {
+    height: 100%;
+    :deep(.el-card__body) {
+      height: calc(100% - 70px);
+    }
+  }
+  .btn {
+    margin-top: 32px;
+    display: flex;
+    justify-content: center;
+    .el-button {
+      padding: 0 32px;
+    }
+  }
+  .w-50 {
+    width: 21.5rem;
+  }
+  .input-suffix {
+    width: 100%;
+    .inline-flex {
+      white-space: nowrap;
+    }
+    .d-flex {
+      display: flex;
+    }
+  }
+}

+ 1 - 3
src/views/workAttendance/MyLeave.vue

@@ -276,9 +276,7 @@ onMounted(() => {
           />
         </el-form-item>
         <el-form-item label="请假时长:" :label-width="formLabelWidth" prop="T_duration">
-          <el-input v-model="form.T_duration" disabled placeholder="请假时长"
-            ><template #suffix> 小时 </template></el-input
-          >
+          <el-input v-model="form.T_duration" placeholder="请假时长"><template #suffix> 小时 </template></el-input>
         </el-form-item>
         <el-form-item label="内容:" :label-width="formLabelWidth">
           <el-input

+ 30 - 30
vite.config.ts

@@ -22,22 +22,22 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
     },
     server: {
       open: true,
-      host: '0.0.0.0'
-      // proxy: {
-      //   '/api': {
-      //     target: 'https://erp.baozhida.cn',
-      //     changeOrigin: true,
-      //     rewrite: path => path.replace(/^\/api/, '/testapi')
-      //   },
-      //   '/testapi': {
-      //     target: 'https://erp.baozhida.cn',
-      //     changeOrigin: true
-      //   },
-      //   '/ams': {
-      //     target: 'http://erp.baozhida.cn',
-      //     changeOrigin: true
-      //   }
-      // }
+      host: '0.0.0.0',
+      proxy: {
+        '/api': {
+          target: 'https://erp.baozhida.cn',
+          changeOrigin: true,
+          rewrite: path => path.replace(/^\/api/, '/testapi')
+        },
+        '/testapi': {
+          target: 'https://erp.baozhida.cn',
+          changeOrigin: true
+        },
+        '/ams': {
+          target: 'http://erp.baozhida.cn',
+          changeOrigin: true
+        }
+      }
     },
     plugins: [
       vue(),
@@ -61,20 +61,20 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
     // * 打包去除 console.log && debugger
     esbuild: {
       pure: env.VITE_DROP_CONSOLE ? ['console.log', 'debugger'] : []
+    },
+    build: {
+      // rollupOptions: {
+      //   output: {
+      //     // 打包后文件命名
+      //     assetFileNames: '[hash].[name].[ext]'
+      //   }
+      // },
+      // // 图片大小分界线:大于 4kb,图片正常打包。小于 4kb,图片会转化为 base64。
+      // assetsInlineLimit: 4096, // 4kb
+      // 打包后名称,默认是 dist
+      outDir: 'ERP'
+      // 打包后静态目录名称
+      // assetsDir: 'static'
     }
-    // build: {
-    //   rollupOptions: {
-    //     output: {
-    //       // 打包后文件命名
-    //       assetFileNames: '[hash].[name].[ext]'
-    //     }
-    //   },
-    //   // 图片大小分界线:大于 4kb,图片正常打包。小于 4kb,图片会转化为 base64。
-    //   assetsInlineLimit: 4096, // 4kb
-    //   // 打包后名称,默认是 dist
-    //   outDir: 'testDir',
-    //   // 打包后静态目录名称
-    //   assetsDir: 'static'
-    // }
   }
 })