Browse Source

feat: ✨ 完成出库以及出库详情

@sun-chaoqun 2 years ago
parent
commit
d4477d6f57

+ 1 - 1
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,
   // 跨域时候允许携带凭证

+ 2 - 0
src/api/storehouse/index.ts

@@ -74,6 +74,8 @@ export const Storehouse_Contract_Del = (params: any) => $http.post('/testapi/sto
 // 产品列表
 export const Storehouse_Contract_Product_List = (params: any) =>
   $http.post('/testapi/storage/Contract/Product_List', params)
+// 获取为出库或为完全出库合同列表
+export const Storehouse_Contract_Out_List = (params: any) => $http.post('/testapi/storage/Contract/Out_List', params)
 
 /**
  * 库存管理

+ 28 - 9
src/layouts/Header/index.vue

@@ -4,7 +4,7 @@ import { useRouter } from 'vue-router'
 import { GlobalStore } from '@/stores/index'
 import Breadcrumb from './Breadcrumb.vue'
 // import Notice from './Notice.vue'
-import { Expand, Fold, List } from '@element-plus/icons-vue'
+import { Expand, Fold, List, SwitchButton, UserFilled } from '@element-plus/icons-vue'
 import 'element-plus/theme-chalk/src/dropdown.scss'
 const globalStore = GlobalStore()
 const router = useRouter()
@@ -72,14 +72,10 @@ setInterval(() => {
           </template>
         </el-dropdown>
       </el-col>
-      <el-col :xl="1" :sm="1" class="notice">
-        <el-avatar>
-          <img src="@/assets/images/avatar.jpg" />
-        </el-avatar>
-      </el-col>
-      <el-col :xl="2" :lg="3" :sm="3" class="notice">
+      <el-col :xl="3" :lg="4" :sm="4" class="notice">
         <el-dropdown>
           <div class="avatar">
+            <el-avatar> <img src="@/assets/images/avatar.jpg" /> </el-avatar>
             <span>{{ globalStore.GET_User_Info.T_name }}</span>
             <el-icon class="el-icon">
               <arrow-down />
@@ -87,14 +83,30 @@ setInterval(() => {
           </div>
           <template #dropdown>
             <el-dropdown-menu>
-              <el-dropdown-item @click="logOut">退出登录</el-dropdown-item>
-              <el-dropdown-item @click="router.push('/user')">个人中心</el-dropdown-item>
+              <el-dropdown-item :icon="UserFilled" @click="router.push('/user')">个人中心</el-dropdown-item>
+              <el-dropdown-item :icon="SwitchButton" @click="logOut">退出登录</el-dropdown-item>
             </el-dropdown-menu>
           </template>
         </el-dropdown>
       </el-col>
       <el-col :xl="2" :sm="3" class="notice">{{ time }}</el-col>
     </el-row>
+    <!-- <el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
+      <div style="flex-grow: 1" />
+      <el-menu-item index="1">Element Plus</el-menu-item>
+      <el-sub-menu index="2">
+        <template #title>Workspace</template>
+        <el-menu-item index="2-1">item one</el-menu-item>
+        <el-menu-item index="2-2">item two</el-menu-item>
+        <el-menu-item index="2-3">item three</el-menu-item>
+        <el-sub-menu index="2-4">
+          <template #title>item four</template>
+          <el-menu-item index="2-4-1">item one</el-menu-item>
+          <el-menu-item index="2-4-2">item two</el-menu-item>
+          <el-menu-item index="2-4-3">item three</el-menu-item>
+        </el-sub-menu>
+      </el-sub-menu>
+    </el-menu> -->
   </div>
 </template>
 
@@ -103,6 +115,10 @@ setInterval(() => {
   width: 100%;
   color: #fff;
   // background-color: rgba(18, 21, 39, 0.86);
+  .el-menu-demo {
+    color: #fff;
+    background-color: rgba(18, 21, 39, 0.86);
+  }
   .notice {
     cursor: pointer;
     display: flex;
@@ -125,6 +141,9 @@ setInterval(() => {
     .el-icon {
       color: #fff;
     }
+    span {
+      margin-left: 0.5rem;
+    }
   }
 }
 </style>

+ 137 - 129
src/router/modules/staticRouter.ts

@@ -1,5 +1,5 @@
 import { RouteRecordRaw } from 'vue-router'
-import { h, defineComponent } from 'vue'
+
 export const staticRouter: RouteRecordRaw[] = [
   {
     path: '/',
@@ -14,134 +14,142 @@ 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/:type',
-            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: '/inStorageDetail/:id',
-            name: 'InStorageDetail',
-            component: () => import('@/views/storehouse/inventory/InStorageDetail.vue'),
-            meta: {
-              title: '入库详情'
-            }
-          },
-          {
-            path: '/outStock',
-            name: 'OutStock',
-            component: () => import('@/views/storehouse/outStock/OutStock.vue'),
-            meta: {
-              title: '出库管理'
-            }
-          },
-          {
-            path: '/receiveOutStock',
-            name: 'ReceiveOutStock',
-            component: () => import('@/views/storehouse/outStock/ReceiveOutStock.vue'),
-            meta: {
-              title: '领料出库'
-            }
-          },
-          {
-            path: '/saleOutStock',
-            name: 'SaleOutStock',
-            component: () => import('@/views/storehouse/outStock/SaleOutStock.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/:type',
+      //       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: '/inStorageDetail/:id',
+      //       name: 'InStorageDetail',
+      //       component: () => import('@/views/storehouse/inventory/InStorageDetail.vue'),
+      //       meta: {
+      //         title: '入库详情'
+      //       }
+      //     },
+      //     {
+      //       path: '/outStock',
+      //       name: 'OutStock',
+      //       component: () => import('@/views/storehouse/outStock/OutStock.vue'),
+      //       meta: {
+      //         title: '出库管理'
+      //       }
+      //     },
+      //     {
+      //       path: '/receiveOutStock',
+      //       name: 'ReceiveOutStock',
+      //       component: () => import('@/views/storehouse/outStock/ReceiveOutStock.vue'),
+      //       meta: {
+      //         title: '领料出库'
+      //       }
+      //     },
+      //     {
+      //       path: '/saleOutStock',
+      //       name: 'SaleOutStock',
+      //       component: () => import('@/views/storehouse/outStock/SaleOutStock.vue'),
+      //       meta: {
+      //         title: '销售出库'
+      //       }
+      //     },
+      //     {
+      //       path: '/outStockDetail/:number',
+      //       name: 'OutStockDetail',
+      //       component: () => import('@/views/storehouse/outStock/OutStockDetail.vue'),
+      //       meta: {
+      //         title: '出库详情'
+      //       }
+      //     }
+      //   ]
+      // },
       // {
       //   path: '/contract',
       //   name: 'Contract',

+ 36 - 22
src/utils/common.ts

@@ -37,31 +37,45 @@ export const getAllBreadcrumbList = (menuList: any, result: { [key: string]: any
   return result
 }
 
-// const path = {
-//   home: ['/home'],
-//   roles: ['/roles'],
-//   users: ['/users'],
-//   salary: ['/salary'],
-//   salarys: ['/salaryCount', '/salaryMy'],
-//   workAttendance: ['/leave', '/myLeave', '/myOvertime', '/overtime', '/recordsFinance'],
-//   records: ['/records']
-// }
+const path = {
+  home: ['/home'],
+  roles: ['/roles'],
+  users: ['/users'],
+  salary: ['/salary'],
+  salarys: ['/salaryCount', '/salaryMy'],
+  workAttendance: ['/leave', '/myLeave', '/myOvertime', '/overtime', '/recordsFinance'],
+  records: ['/records']
+}
 
 const permissionPath = (permission: string): string => {
-  switch (permission) {
-    case '/roles':
-      return '/account/roles'
-    case '/users':
-      return '/account/users'
-    case '/salarys':
-      return '/salarys'
-    case '/workAttendance':
-      return '/workAttendance'
-    case '/records':
-      return '/workAttendance/records'
-    default:
-      return '/home'
+  if (path.roles.includes(permission)) {
+    return '/account/roles'
+  } else if (path.users.includes(permission)) {
+    return '/account/users'
+  } else if (path.salarys.includes(permission)) {
+    return '/salary'
+  } else if (path.salary.includes(permission)) {
+    return '/salary/salary'
+  } else if (path.workAttendance.includes(permission)) {
+    return '/workAttendance'
+  } else if (path.records.includes(permission)) {
+    return '/workAttendance/records'
   }
+  return '/home'
+  // switch (permission) {
+  //   case '/roles':
+  //     return '/account/roles'
+  //   case '/users':
+  //     return '/account/users'
+  //   case '/salarys':
+  //     return '/salarys'
+  //   case '/workAttendance':
+  //     return '/workAttendance'
+  //   case '/records':
+  //     return '/workAttendance/records'
+  //   default:
+  //     return '/home'
+  // }
 }
 
 const get_name = (name: string): string => {

+ 1 - 0
src/views/Login.vue

@@ -92,6 +92,7 @@ const changeType = () => {
             :prefix-icon="Lock"
             autocomplete="off"
             placeholder="请输入密码"
+            @change="submitForm(ruleFormRef)"
           >
             <template #suffix>
               <span class="view">

+ 4 - 29
src/views/storehouse/inventory/InStorage.vue

@@ -4,7 +4,6 @@ import { GlobalStore } from '@/stores/index'
 import { View } from '@element-plus/icons-vue'
 import InStorageForm from './InStorageForm.vue'
 import { ref, reactive, onMounted } from 'vue'
-import Dialog from '@/components/dialog/Dialog.vue'
 import TableBase from '@/components/TableBase/index.vue'
 import type { ColumnProps } from '@/components/TableBase/interface/index'
 import { Storehouse_StockIn_List, Storehouse_Depot_List } from '@/api/storehouse/index'
@@ -22,18 +21,7 @@ const columns: ColumnProps[] = [
   { prop: 'operation', label: '操作', width: 260, fixed: 'right' }
 ]
 
-/**
- * 查看图片
- */
-const url = ref('')
-const srcList = ref<any[]>([])
-const dialog = ref<InstanceType<typeof Dialog> | null>(null)
 const InStorageFormRef = ref<InstanceType<typeof InStorageForm> | null>(null)
-const previewImg = (str: string) => {
-  dialog.value?.DialogOpen()
-  url.value = str
-  srcList.value.push(str)
-}
 /**
  * 查看详情
  */
@@ -68,7 +56,10 @@ interface ItemType {
 }
 const options = ref<ItemType[]>([])
 const getDepotList = async () => {
-  if (globalStore.GET_depotList.length) return
+  if (globalStore.GET_depotList.length) {
+    options.value = globalStore.GET_depotList
+    return
+  }
   const res: any = await Storehouse_Depot_List({ User_tokey: globalStore.GET_User_tokey, page: 1, page_z: 999 })
   options.value = res.Data.Data
   globalStore.SET_depotList(options.value)
@@ -109,26 +100,10 @@ onMounted(() => {
           </el-row>
         </div>
       </template>
-      <template #T_State="{ row }">
-        <el-tag v-if="row.T_State === 1" type="success" effect="dark"> 已出库 </el-tag>
-        <el-tag v-else type="danger" effect="dark"> 未出库 </el-tag>
-      </template>
-      <template #T_product_img="{ row }">
-        <el-image
-          v-if="row.T_product_img"
-          style="height: 50px"
-          :src="row.T_product_img"
-          fit="cover"
-          @click="previewImg(row.T_product_img)"
-        />
-      </template>
       <template #right="{ row }">
         <el-button link type="success" size="small" :icon="View" @click="preview(row.T_number)">详情</el-button>
       </template>
     </TableBase>
-    <Dialog ref="dialog" width="50%">
-      <el-image :src="url" :zoom-rate="1.2" :preview-src-list="srcList" fit="cover" />
-    </Dialog>
     <InStorageForm ref="InStorageFormRef" :options="options" @onUpdateList="searchHandle" />
   </div>
 </template>

+ 58 - 4
src/views/storehouse/inventory/InStorageDetail.vue

@@ -3,6 +3,7 @@ import { ref, onMounted } from 'vue'
 import { GlobalStore } from '@/stores/index'
 import { useRoute, useRouter } from 'vue-router'
 import { Storehouse_StockIn_Get } from '@/api/storehouse/index'
+import Drawer from '@/components/Drawer/index.vue'
 
 interface InfoType {
   Id: number
@@ -14,8 +15,11 @@ interface InfoType {
   T_submit_name: string
 }
 
-const info = ref<InfoType | undefined>()
+const tableData = ref<any[]>([])
+const tableSnData = ref<any[]>([])
 const globalStore = GlobalStore()
+const info = ref<InfoType | undefined>()
+const drawerSnRef = ref<InstanceType<typeof Drawer> | null>(null)
 const route = useRoute()
 const router = useRouter()
 
@@ -30,6 +34,12 @@ const columns = [
   { label: '数量', prop: 'T_num', align: 'center ' },
   { prop: 'operation', label: '关联设备', width: 100, fixed: 'right', align: 'center ' }
 ]
+
+const snColumns = [
+  { type: 'index', label: '序号', width: 80, align: 'center ' },
+  { label: 'SN', prop: 'sn', align: 'center ' }
+]
+
 const getStorehouseContractGet = async () => {
   const res: any = await Storehouse_StockIn_Get({ User_tokey: globalStore.GET_User_tokey, T_number: route.params.id })
   if (res.Code === 200) {
@@ -38,7 +48,28 @@ const getStorehouseContractGet = async () => {
   }
 }
 
-const tableData = ref<any[]>([])
+/**
+ * 回调
+ */
+const callbackSnDrawer = (done: () => void) => done()
+
+const previewSn = (devicelist: string[]) => {
+  drawerSnRef.value?.openDrawer()
+  tableSnData.value = devicelist.map((item: string) => {
+    return {
+      sn: item
+    }
+  })
+}
+/**
+ * 查看图片
+ */
+const srcList = ref<any[]>([])
+const previewImg = (str: string) => {
+  // dialog.value?.DialogOpen()
+  // url.value = str
+  srcList.value.push(str)
+}
 
 onMounted(() => {
   getStorehouseContractGet()
@@ -93,8 +124,11 @@ onMounted(() => {
                       v-if="item.prop === 'T_product_img'"
                       style="height: 50px"
                       :src="row.T_product_img"
-                      :preview-src-list="srcList"
+                      :zoom-rate="1.2"
+                      :preview-src-list="[row.T_product_img]"
+                      :preview-teleported="true"
                       fit="cover"
+                      @click="previewImg(row.T_product_img)"
                     />
                     <el-tooltip
                       v-if="item.prop === 'T_product_model'"
@@ -108,7 +142,12 @@ onMounted(() => {
                 </el-table-column>
                 <el-table-column v-bind="item" v-if="item.fixed === 'right'">
                   <template #default="{ row }">
-                    <el-button type="primary" :disabled="!row.T_product_relation_sn">查看</el-button>
+                    <el-button
+                      type="primary"
+                      :disabled="!row.T_product_relation_sn"
+                      @click="previewSn(row.T_device_list)"
+                      >查看</el-button
+                    >
                   </template>
                 </el-table-column>
               </template>
@@ -127,6 +166,21 @@ onMounted(() => {
         <el-button type="primary" round @click="router.back()">返回</el-button>
       </div>
     </div>
+    <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="30%">
+      <el-table
+        :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" v-bind="item" />
+        </template>
+      </el-table>
+    </Drawer>
   </div>
 </template>
 

+ 1 - 1
src/views/storehouse/inventory/InStorageSn.vue

@@ -79,7 +79,7 @@ defineExpose({
 </script>
 
 <template>
-  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
+  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="30%">
     <el-card class="box-card" shadow="never">
       <template #header>
         <div class="sn-header">

+ 96 - 0
src/views/storehouse/outStock/ContractNumber.vue

@@ -0,0 +1,96 @@
+<script setup lang="ts">
+import { ref } from 'vue'
+import { Storehouse_Contract_Out_List } from '@/api/storehouse/index'
+// import Dialog from '@/components/dialog/Dialog.vue'
+import Drawer from '@/components/Drawer/index.vue'
+import { GlobalStore } from '@/stores/index'
+import TableBase from '@/components/TableBase/index.vue'
+import { ColumnProps } from '@/components/TableBase/interface/index'
+
+const search = ref('')
+const globalStore = GlobalStore()
+const drawer = ref<InstanceType<typeof Drawer> | null>(null)
+const tableRef = ref<InstanceType<typeof TableBase> | null>(null)
+
+const Dialogcolumns: ColumnProps[] = [
+  { type: 'index', label: '序号', width: 80 },
+  { prop: 'T_number', label: '合同编号' },
+  { prop: 'T_customer', label: '客户名称' },
+  { prop: 'T_out', label: '出库状态', name: 'T_out' }
+]
+const InitParam = {
+  User_tokey: globalStore.GET_User_tokey,
+  T_name: '',
+  T_dept_leader: 1
+}
+const searchHandle = () => {
+  InitParam.T_name = search.value
+  tableRef.value?.searchTable()
+}
+/**
+ * 获取信息
+ */
+const getApproverInfo = (row: any) => {
+  emit('onContactInfo', row)
+  drawer.value?.closeDrawer()
+}
+
+const emit = defineEmits<{ (event: 'onContactInfo', value: any): void }>()
+
+/**
+ * 配置高度
+ */
+const onResize = () => {
+  const height = document.documentElement.clientHeight
+  return height - 45 - 74 - 40 - 12
+}
+
+const openDrawer = () => drawer.value?.openDrawer()
+defineExpose({
+  openDrawer
+})
+</script>
+
+<template>
+  <Drawer ref="drawer" size="50%">
+    <template #header="{ params }">
+      <h3 :id="params.titleId" :class="params.titleClass">合同编号</h3>
+    </template>
+    <TableBase
+      ref="tableRef"
+      :columns="Dialogcolumns"
+      :initParam="InitParam"
+      :requestApi="Storehouse_Contract_Out_List"
+      layout="total, prev, pager, next"
+      :onResize="onResize"
+      :rowClick="getApproverInfo"
+    >
+      <template #table-header>
+        <el-row :gutter="20">
+          <el-col :span="24" class="d-flex">
+            <span class="inline-flex">合同编号:</span>
+            <el-input v-model="search" type="text" placeholder="按合同编号搜索" />
+            <el-button type="primary" @click="searchHandle">搜索</el-button>
+          </el-col>
+        </el-row>
+      </template>
+      <template #T_out="{ row }">
+        <el-tag v-if="row.T_out === 2 || row.T_out === 3" type="success" effect="dark">
+          {{ row.T_out === 2 ? '已部分出库' : '已全部出库' }}
+        </el-tag>
+        <el-tag v-else-if="row.T_out === 1" type="warning" effect="dark"> 未出库 </el-tag>
+        <el-tag v-else type="danger" effect="dark"> --- </el-tag>
+      </template>
+    </TableBase>
+  </Drawer>
+</template>
+
+<style scoped>
+.inline-flex {
+  white-space: nowrap;
+}
+.d-flex {
+  display: flex;
+  align-items: center;
+}
+</style>

+ 3 - 3
src/views/storehouse/outStock/OutStock.vue

@@ -28,7 +28,7 @@ const delivery_type = [
 const columns: ColumnProps[] = [
   { type: 'index', label: '序号', width: 80 },
   { prop: 'T_number', label: '出库单号' },
-  { prop: 'T_receive_name', label: '领取人' },
+  { prop: 'T_receive', label: '领取人' },
   { prop: 'T_depot_name', label: '出库仓库' },
   { prop: 'T_date', label: '出库日期' },
   { prop: 'T_type', label: '出库类型', name: 'T_type' },
@@ -58,8 +58,8 @@ const rules = reactive<FormRules>({
 /**
  * 查看详情
  */
-const preview = (id: string) => {
-  router.push({ name: 'InStorageDetail', params: { id } })
+const preview = (number: string) => {
+  router.push({ name: 'OutStockDetail', params: { number } })
 }
 
 // 搜索

+ 157 - 0
src/views/storehouse/outStock/OutStockDetail.vue

@@ -0,0 +1,157 @@
+<script setup lang="ts">
+import { ref, onMounted } from 'vue'
+import { GlobalStore } from '@/stores/index'
+import { useRoute, useRouter } from 'vue-router'
+import { Storehouse_StockOut_Get } from '@/api/storehouse/index'
+
+interface InfoType {
+  Id: number
+  T_depot_name: string
+  T_date: string
+  T_number: string
+  T_remark: string
+  T_submit: string
+  T_submit_name: string
+}
+
+const info = ref<InfoType | undefined>()
+const globalStore = GlobalStore()
+const route = useRoute()
+const router = useRouter()
+
+const columns = [
+  { type: 'index', label: '序号', width: 80, align: 'center ' },
+  { label: '产品图片', prop: 'T_product_img', align: 'center ', name: 'T_product_img' },
+  { label: '产品名称', prop: 'T_product_name', align: 'center ' },
+  { label: '产品分类', prop: 'T_product_class_name', align: 'center ' },
+  { label: '产品型号', prop: 'T_product_model', align: 'center ', name: 'T_product_model' },
+  { label: '产品规格', prop: 'T_product_spec', align: 'center ' },
+  { label: '是否关联SN', prop: 'T_product_relation_sn', align: 'center ', width: 120, name: 'T_product_relation_sn' },
+  { label: '数量', prop: 'T_num', align: 'center ' },
+  { prop: 'operation', label: '关联设备', width: 100, fixed: 'right', align: 'center ' }
+]
+const getStorehouseContractGet = async () => {
+  const res: any = await Storehouse_StockOut_Get({
+    User_tokey: globalStore.GET_User_tokey,
+    T_number: route.params.number
+  })
+  if (res.Code === 200) {
+    info.value = res.Data
+    tableData.value = res.Data.T_Product
+  }
+}
+
+const tableData = ref<any[]>([])
+
+onMounted(() => {
+  getStorehouseContractGet()
+})
+</script>
+<template>
+  <div class="contract-detail">
+    <div class="info">
+      <h1>入库详情</h1>
+      <el-divider />
+      <div class="content">
+        <el-row>
+          <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"><span>入库单号:</span></el-col>
+          <el-col :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+            ><span>{{ info?.T_number! }}</span></el-col
+          >
+        </el-row>
+        <el-row>
+          <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"> <span>入库仓库:</span></el-col>
+          <el-col :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+            ><span>{{ info?.T_depot_name! }}</span></el-col
+          >
+        </el-row>
+        <el-row>
+          <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"> <span>入库日期:</span></el-col>
+          <el-col :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+            ><span>{{ info?.T_date! }}</span></el-col
+          >
+        </el-row>
+        <el-row>
+          <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"><span>入库明细:</span></el-col>
+          <el-col :span="21">
+            <el-table
+              :data="tableData"
+              style="width: 100%"
+              border
+              stripe
+              :header-cell-style="{
+                background: '#909399',
+                height: '50px',
+                color: '#fff'
+              }"
+            >
+              <template v-for="item in columns" :key="item.prop">
+                <el-table-column v-bind="item" v-if="item.fixed !== 'right'">
+                  <template #default="{ row }" v-if="item.prop === item.name">
+                    <span v-if="item.prop === 'T_product_relation_sn'">
+                      <el-tag v-if="row.T_product_relation_sn === 1" effect="dark">是</el-tag>
+                      <el-tag v-else type="success" effect="dark">否</el-tag>
+                    </span>
+                    <el-image
+                      v-if="item.prop === 'T_product_img'"
+                      style="height: 50px"
+                      :src="row.T_product_img"
+                      :preview-src-list="[row.T_product_img]"
+                      fit="cover"
+                    />
+                    <el-tooltip
+                      v-if="item.prop === 'T_product_model'"
+                      effect="dark"
+                      :content="row.T_product_model"
+                      placement="bottom"
+                    >
+                      {{ row.T_product_model }}
+                    </el-tooltip>
+                  </template>
+                </el-table-column>
+                <el-table-column v-bind="item" v-if="item.fixed === 'right'">
+                  <template #default="{ row }">
+                    <el-button type="primary" :disabled="!row.T_product_relation_sn">查看</el-button>
+                  </template>
+                </el-table-column>
+              </template>
+            </el-table>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"><span>备注:</span></el-col>
+          <el-col :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+            ><span>{{ info?.T_remark! }}</span></el-col
+          >
+        </el-row>
+      </div>
+      <el-divider />
+      <div class="submit">
+        <el-button type="primary" round @click="router.back()">返回</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<style scoped lang="scss">
+.contract-detail {
+  height: 100%;
+  font-weight: bold;
+  color: var(--el-text-color-secondary);
+  .info {
+    height: 100%;
+    padding: 20px;
+    & .content {
+      height: calc(100% - 72px - 25px - 40px);
+      overflow-y: scroll;
+      .el-row {
+        margin-bottom: 16px;
+      }
+    }
+    .submit {
+      display: flex;
+      justify-content: center;
+    }
+  }
+}
+</style>

+ 8 - 23
src/views/storehouse/outStock/ReceiveOutStock.vue

@@ -3,15 +3,13 @@ import { ElMessage } from 'element-plus'
 import { ref, reactive, nextTick } from 'vue'
 import { useRouter } from 'vue-router'
 import { GlobalStore } from '@/stores/index'
-import Drawer from '@/components/Drawer/index.vue'
 import type { FormInstance, FormRules } from 'element-plus'
 import { Delete, CirclePlus } from '@element-plus/icons-vue'
-import { Storehouse_StockOut_Add, Storehouse_ProductClass_List } from '@/api/storehouse/index'
+import { Storehouse_StockOut_Add } from '@/api/storehouse/index'
 import ReceiveUser from './receiveUser.vue'
 import InStorageSn from '../inventory/InStorageSn.vue'
 import InStorageProduct from '../inventory/InStorageProduct.vue'
 
-// type Fn = () => void
 interface FormType {
   T_type: number
   T_uuid: string
@@ -30,10 +28,8 @@ const globalStore = GlobalStore()
 const formLabelWidth = ref('120px')
 const ruleFormRef = ref<FormInstance>()
 const receiveUserdialog = ref<InstanceType<typeof ReceiveUser> | null>(null)
-const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
 const drawerSnRef = ref<InstanceType<typeof InStorageSn> | null>(null)
 const drawerProductRef = ref<InstanceType<typeof InStorageProduct> | null>(null)
-const classOptions = ref<any[]>([])
 
 const form = reactive<FormType>({
   T_type: 1,
@@ -134,9 +130,7 @@ const AddInStorage = (formEl: FormInstance | undefined) => {
         ElMessage.success('出库成功!')
         drawerProductRef.value?.clearSelection()
         nextTick(() => {
-          // emit('onUpdateList')
           resetForm(ruleFormRef.value)
-          // drawerRef.value?.closeDrawer()
           router.back()
         })
       }
@@ -165,21 +159,10 @@ const resetForm = (formEl: FormInstance | undefined) => {
   tableData.value = []
   formEl.resetFields()
 }
-
-/**
- * 获取产品分类
- */
-const getProductClassList = async () => {
-  const res: any = await Storehouse_ProductClass_List({ page: 1, page_z: 999 })
-  classOptions.value = res.Data.Data
-}
 /**
  * 添加产品
  */
-const AddProductionDetailed = () => {
-  !classOptions.value.length && getProductClassList()
-  drawerProductRef.value?.openDrawer()
-}
+const AddProductionDetailed = () => drawerProductRef.value?.openDrawer()
 /**
  * 产品选择 是否
  */
@@ -219,7 +202,7 @@ const autoGetCount = (length: number, id: number) => {
 /**
  * 选择经办人
  */
-const selectApprover = () => receiveUserdialog.value?.openDialog()
+const selectApprover = () => receiveUserdialog.value?.openDrawer()
 const getReceiveInfo = ({ T_uuid, T_name }: { T_uuid: string; T_name: string }) => {
   form.T_receive = T_name
   form.T_uuid = T_uuid
@@ -234,9 +217,11 @@ const options = globalStore.GET_depotList
 
 <template>
   <div class="receive-outStock">
-    <h4 class="title">领料出库</h4>
-    <el-form ref="ruleFormRef" :model="form" :rules="rules">
+    <div>
+      <h4 class="title">领料出库</h4>
       <el-divider border-style="dashed" />
+    </div>
+    <el-form ref="ruleFormRef" :model="form" :rules="rules">
       <el-form-item label="出库单号:" :label-width="formLabelWidth" prop="T_number">
         <el-input v-model="form.T_number" disabled type="text" placeholder="系统自动生成" class="w-50" />
       </el-form-item>
@@ -248,7 +233,7 @@ const options = globalStore.GET_depotList
       <el-form-item label="出库日期:" :label-width="formLabelWidth" prop="T_date">
         <el-date-picker
           class="my-date-picker"
-          style="width: 21.5rem"
+          style="flex: 0 0 33.33%"
           v-model="form.T_date"
           type="date"
           placeholder="选择日期"

+ 317 - 12
src/views/storehouse/outStock/SaleOutStock.vue

@@ -1,17 +1,14 @@
 <script setup lang="ts">
+import { ElMessage } from 'element-plus'
 import { ref, reactive, nextTick } from 'vue'
 import { useRouter } from 'vue-router'
 import { GlobalStore } from '@/stores/index'
 import type { FormInstance, FormRules } from 'element-plus'
 import { Delete, CirclePlus } from '@element-plus/icons-vue'
-import {
-  Storehouse_StockOut_Add,
-  Storehouse_ProductClass_List,
-  Storehouse_Contract_Product_List
-} from '@/api/storehouse/index'
 import ReceiveUser from './receiveUser.vue'
 import InStorageSn from '../inventory/InStorageSn.vue'
-import InStorageProduct from '../inventory/InStorageProduct.vue'
+import ContractNumber from './ContractNumber.vue'
+import { Storehouse_StockOut_Add, Storehouse_Contract_Product_List } from '@/api/storehouse/index'
 
 interface FormType {
   T_type: number
@@ -23,6 +20,12 @@ interface FormType {
   T_date: string
   T_remark: string
   T_contract_number: string
+  T_delivery_type: string
+  T_signer_unit: string
+  T_signer: string
+  T_signer_phone: string
+  T_signer_date: string
+  T_courier_number: string
 }
 
 const router = useRouter()
@@ -30,8 +33,11 @@ const tableData = ref<any[]>([])
 const globalStore = GlobalStore()
 const formLabelWidth = ref('120px')
 const ruleFormRef = ref<FormInstance>()
+const drawerSnRef = ref<InstanceType<typeof InStorageSn> | null>(null)
+const receiveUserdialog = ref<InstanceType<typeof ReceiveUser> | null>(null)
+const contractNumberRef = ref<InstanceType<typeof ContractNumber> | null>(null)
 const form = reactive<FormType>({
-  T_type: 1,
+  T_type: 2,
   T_uuid: '',
   T_receive: '',
   T_number: '',
@@ -39,9 +45,37 @@ const form = reactive<FormType>({
   T_product: '',
   T_date: '',
   T_remark: '',
+  T_delivery_type: '',
+  T_signer_unit: '',
+  T_signer: '',
+  T_signer_phone: '',
+  T_signer_date: '',
+  T_courier_number: '',
   T_contract_number: ''
 })
 
+const delivery_type = [
+  { name: '自送', id: 1 },
+  { name: '自提', id: 2 },
+  { name: '快递', id: 3 }
+]
+
+const columns = [
+  { type: 'index', label: '序号', width: 80, align: 'center ' },
+  { label: '产品图片', prop: 'T_product_img', align: 'center ', name: 'T_product_img', width: 100 },
+  { label: '产品名称', prop: 'T_product_name', align: 'center ' },
+  { label: '产品分类', prop: 'T_product_class_name', align: 'center ' },
+  { label: '产品型号', prop: 'T_product_model', align: 'center ', ellipsis: true },
+  { label: '产品规格', prop: 'T_product_spec', align: 'center ' },
+  { label: '是否关联SN', prop: 'T_product_relation_sn', align: 'center ', width: 120, name: 'T_product_relation_sn' },
+  { label: '库存数量', prop: 'T_stock_total', align: 'center ', width: 100 },
+  { label: '预计出库数量', prop: 'T_product_total', align: 'center ', width: 130 },
+  { label: '已出库数量', prop: 'T_product_out', align: 'center ', width: 120 },
+  { label: '*实际出库数量', prop: 'count', align: 'center ', name: 'count', width: 140 },
+  { label: '*关联设备', prop: 'sn', align: 'center ', name: 'sn', width: 100 },
+  { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
+]
+
 const validate_T_product = (rule: any, value: any, callback: any) => {
   if (value.includes(undefined) || value === '') {
     callback(new Error('请填写产品数量'))
@@ -56,28 +90,299 @@ const rules = reactive<FormRules>({
   T_product: [{ required: true, validator: validate_T_product, trigger: 'blur' }],
   T_receive: [{ required: true, message: '请选择经办人', trigger: 'blur' }],
   T_depot_id: [{ required: true, message: '请选择仓库', trigger: 'blur' }],
-  T_date: [{ required: true, message: '请选择出库日期', trigger: 'blur' }]
+  T_date: [{ required: true, message: '请选择出库日期', trigger: 'blur' }],
+  T_contract_number: [{ required: true, message: '请选择合同编号', trigger: 'blur' }]
 })
 
+const countBlurHandle = () => {
+  form.T_product = tableData.value.map(item => {
+    if (!item.count && item.T_product_relation_sn !== 1) return undefined
+    return `${item.Id},${item.count}|`
+  })
+}
+const getDeviceSnToProduct = () => {
+  const DeviceSnData: any = drawerSnRef.value?.getDeviceSn()
+  const isEmpty = determineSNorCount(DeviceSnData)
+  if (isEmpty && isEmpty === 'count') return [undefined]
+  if (isEmpty && isEmpty === 'sn') return [null]
+
+  return tableData.value.map((item: any) => {
+    let product: any = ''
+    if (item.T_product_relation_sn === 1) {
+      DeviceSnData?.forEach((value: any, key: number) => {
+        if (item.Id === key) {
+          let str = ''
+          value.forEach(
+            (snObj: any, index: number, arr: any[]) => (str += `${snObj.sn}${index === arr.length - 1 ? '' : ','}`)
+          )
+          product = `${item.Id}-${item.count}-${str}`
+        }
+      })
+    } else {
+      product = `${item.Id}-${item.count}-`
+    }
+    return product + '|'
+  })
+}
+/**
+ * 判断sn or 数量是否为空
+ */
+const determineSNorCount = (DeviceSnData: any) => {
+  for (const item of tableData.value) {
+    if (!item.count && item.T_product_relation_sn !== 1) return 'count'
+    if (item.T_product_relation_sn === 1 && !DeviceSnData.get(item.Id) && !DeviceSnData.size) return 'sn'
+  }
+  return false
+}
+
+/**
+ * 添加sn 号
+ */
+const addDeviceSn = (id: number) => {
+  drawerSnRef.value?.addDeviceSn(id)
+}
+/**
+ * 自动计算 count
+ */
+const autoGetCount = (length: number, id: number) => {
+  tableData.value.forEach((item: any) => {
+    if (item.Id === id) {
+      item.count = length
+    }
+  })
+}
+/**
+ * 选择经办人
+ */
+const selectApprover = () => receiveUserdialog.value?.openDrawer()
+const getReceiveInfo = ({ T_uuid, T_name }: { T_uuid: string; T_name: string }) => {
+  form.T_receive = T_name
+  form.T_uuid = T_uuid
+}
+/**
+ * 选择合同
+ */
+const selectContract = () => contractNumberRef.value?.openDrawer()
+const getContactInfo = ({ T_number }: { T_number: string }) => {
+  if (form.T_contract_number === T_number) return
+  form.T_contract_number = T_number
+  getProductList(T_number)
+}
+/**
+ * 通过合同获取产品
+ */
+const getProductList = async (T_number: string) => {
+  const res: any = await Storehouse_Contract_Product_List({ User_tokey: globalStore.GET_User_tokey, T_number })
+  console.log(res)
+  if (res.Code === 200 && res.Data.length) {
+    tableData.value = res.Data
+  }
+}
+/**
+ * 删除产品
+ */
+const deleteProduct = (row: any) => {
+  tableData.value = tableData.value.filter(item => item.Id !== row.Id)
+
+  // 设置产品的选中
+  // drawerProductRef.value?.selectTableChange(row)
+  // 删除设备得sn
+  drawerSnRef.value?.deleteDeviceSn(row.Id)
+}
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  tableData.value = []
+  formEl.resetFields()
+}
+/**
+ * 取消出库
+ */
+const closeSaleOutStock = () => {
+  resetForm(ruleFormRef.value)
+  router.back()
+}
+/**
+ * 提交内容
+ */
+const AddSaleOutStock = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  form.T_product = getDeviceSnToProduct()
+  formEl.validate(async valid => {
+    if (valid) {
+      const res: any = await Storehouse_StockOut_Add({
+        User_tokey: globalStore.GET_User_tokey,
+        ...form,
+        T_product: form.T_product.join('')
+      })
+      console.log(res)
+      if (res.Code === 200) {
+        ElMessage.success('出库成功!')
+        nextTick(() => {
+          closeSaleOutStock()
+        })
+      }
+    }
+  })
+}
+
 const options = globalStore.GET_depotList
 </script>
 <template>
   <div class="receive-outStock">
-    <h4 class="title">销售出库</h4>
-    <el-form ref="ruleFormRef" :model="form" :rules="rules">
+    <div>
+      <h4 class="title">销售出库</h4>
       <el-divider border-style="dashed" />
+    </div>
+    <el-form ref="ruleFormRef" :model="form" :rules="rules">
       <el-form-item label="出库单号:" :label-width="formLabelWidth" prop="T_number">
         <el-input v-model="form.T_number" disabled type="text" placeholder="系统自动生成" class="w-50" />
       </el-form-item>
-      <el-form-item label="合同编号:" :label-width="formLabelWidth" prop="T_number">
-        <el-input v-model="form.T_number" type="text" placeholder="请选择合同编号" class="w-50" />
+      <el-form-item label="合同编号:" :label-width="formLabelWidth" prop="T_contract_number">
+        <el-input
+          v-model="form.T_contract_number"
+          type="text"
+          placeholder="请选择合同编号"
+          class="w-50"
+          @click="selectContract"
+        />
       </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="请选择入库仓库~">
           <el-option v-for="item in options" :key="item.Id" :label="item.T_name" :value="item.Id" />
         </el-select>
       </el-form-item>
+      <el-form-item label="出库日期:" :label-width="formLabelWidth" prop="T_date">
+        <el-date-picker
+          class="my-date-picker"
+          style="flex: 0 0 33.33%"
+          v-model="form.T_date"
+          type="date"
+          placeholder="选择日期"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+      <el-form-item label="经办人:" :label-width="formLabelWidth" prop="T_receive">
+        <el-input
+          v-model="form.T_receive"
+          type="text"
+          placeholder="请选择经办人"
+          class="w-50"
+          @click="selectApprover"
+        />
+      </el-form-item>
+      <el-form-item label="出库明细:" :label-width="formLabelWidth" prop="T_product">
+        <el-table
+          :data="tableData"
+          style="width: 100%"
+          border
+          stripe
+          :header-cell-style="{
+            background: '#dedfe0',
+            height: '50px'
+          }"
+        >
+          <template v-for="item in columns" :key="item.prop">
+            <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' && row.T_product_relation_sn !== 1"
+                  v-model.number="row.count"
+                  type="text"
+                  autocomplete="off"
+                  @blur="countBlurHandle"
+                />
+                <div v-if="item.prop === 'sn'">
+                  <el-button
+                    v-if="row.T_product_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_product_relation_sn'">
+                  <el-tag v-if="row.T_product_relation_sn === 1" effect="dark">是</el-tag>
+                  <el-tag v-else type="success" effect="dark">否</el-tag>
+                </span>
+                <el-image
+                  v-if="item.prop === 'T_product_img'"
+                  style="height: 50px"
+                  :src="row.T_product_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>
+              </template>
+            </el-table-column>
+          </template>
+        </el-table>
+      </el-form-item>
+      <el-form-item label="送货方式:" :label-width="formLabelWidth" prop="T_delivery_type">
+        <el-select v-model="form.T_delivery_type" clearable placeholder="请选择送货方式~" class="w-50">
+          <el-option v-for="item in delivery_type" :key="item.id" :label="item.name" :value="item.id" />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="签收单位:" :label-width="formLabelWidth" prop="T_signer_unit">
+        <el-input v-model="form.T_signer_unit" type="text" placeholder="请输入签收单位" class="w-50" />
+      </el-form-item>
+      <el-form-item label="签收人:" :label-width="formLabelWidth" prop="T_signer">
+        <el-input v-model="form.T_signer" type="text" placeholder="请输入签收人" class="w-50" />
+      </el-form-item>
+      <el-form-item label="签收人电话:" :label-width="formLabelWidth" prop="T_signer_phone">
+        <el-input v-model="form.T_signer_phone" type="text" placeholder="请输入签收人电话" class="w-50" />
+      </el-form-item>
+      <el-form-item label="签收日期:" :label-width="formLabelWidth" prop="T_signer_date">
+        <el-date-picker
+          class="my-date-picker"
+          style="flex: 0 0 33.33%"
+          v-model="form.T_signer_date"
+          type="date"
+          placeholder="选择签收日期"
+          format="YYYY-MM-DD"
+          value-format="YYYY-MM-DD"
+        />
+      </el-form-item>
+      <el-form-item label="物流单号:" :label-width="formLabelWidth" prop="T_courier_number">
+        <el-input v-model="form.T_courier_number" type="text" placeholder="请输入物流单号" class="w-50" />
+      </el-form-item>
+      <el-form-item label="备注:" :label-width="formLabelWidth" prop="T_remark">
+        <el-input
+          v-model="form.T_remark"
+          :autosize="{ minRows: 4, maxRows: 6 }"
+          type="textarea"
+          placeholder="请输入备注信息"
+        />
+      </el-form-item>
+      <div class="btn">
+        <el-divider>
+          <el-button @click="closeSaleOutStock">取消</el-button>
+          <el-button color="#626aef" @click="AddSaleOutStock(ruleFormRef)">提交</el-button>
+        </el-divider>
+      </div>
     </el-form>
+    <InStorageSn ref="drawerSnRef" @onCount="autoGetCount" />
+    <ReceiveUser ref="receiveUserdialog" @onUserInfo="getReceiveInfo" />
+    <ContractNumber ref="contractNumberRef" @onContactInfo="getContactInfo" />
   </div>
 </template>
 

+ 9 - 2
src/views/storehouse/outStock/index.scss

@@ -3,6 +3,13 @@
   overflow-y: auto;
 }
 .receive-outStock {
+  height: 100%;
+  // overflow-y: scroll;
+  .el-form {
+    height: 90%;
+    padding: 5px;
+    overflow-y: scroll;
+  }
   .title {
     padding-top: 1rem;
     font-size: 1.5rem;
@@ -20,7 +27,7 @@
     }
   }
   .btn {
-    margin-top: 32px;
+    margin: 32px 0px;
     display: flex;
     justify-content: center;
     .el-button {
@@ -28,7 +35,7 @@
     }
   }
   .w-50 {
-    width: 21.5rem;
+    flex: 0 0 33.33%;
   }
   .input-suffix {
     width: 100%;

+ 38 - 34
src/views/storehouse/outStock/receiveUser.vue

@@ -1,14 +1,15 @@
 <script setup lang="ts">
-import { ref } from 'vue'
+import { nextTick, ref } from 'vue'
 import { User_List } from '@/api/user/index'
-import Dialog from '@/components/dialog/Dialog.vue'
+// import Dialog from '@/components/dialog/Dialog.vue'
+import Drawer from '@/components/Drawer/index.vue'
 import { GlobalStore } from '@/stores/index'
 import TableBase from '@/components/TableBase/index.vue'
 import { ColumnProps } from '@/components/TableBase/interface/index'
 
 const search = ref('')
 const globalStore = GlobalStore()
-const dialog = ref<InstanceType<typeof Dialog> | null>(null)
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
 const tableRef = ref<InstanceType<typeof TableBase> | null>(null)
 
 const Dialogcolumns: ColumnProps[] = [{ prop: 'T_name', label: '名字', name: 'T_name' }]
@@ -25,10 +26,11 @@ const searchHandle = () => {
  * 获取信息
  */
 const getApproverInfo = (row: any) => {
-  // uuid = row.T_uuid
-  // form.value.T_approver = row.T_name
   emit('onUserInfo', row)
-  dialog.value?.DialogClose()
+  drawerRef.value?.closeDrawer()
+}
+const callbackDrawer = (done: () => void) => {
+  done()
 }
 
 const emit = defineEmits<{ (event: 'onUserInfo', value: any): void }>()
@@ -38,42 +40,44 @@ const emit = defineEmits<{ (event: 'onUserInfo', value: any): void }>()
  */
 const onResize = () => {
   const height = document.documentElement.clientHeight
-  return height / 2
+  return height - 45 - 74 - 40 - 12
 }
 
-const openDialog = () => dialog.value?.DialogOpen()
+const openDrawer = () => drawerRef.value?.openDrawer()
 defineExpose({
-  openDialog
+  openDrawer
 })
 </script>
 
 <template>
-  <Dialog ref="dialog" width="30%">
-    <template #header>
-      <h3>选择经办人</h3>
-    </template>
-    <TableBase
-      ref="tableRef"
-      :columns="Dialogcolumns"
-      :initParam="InitParam"
-      :requestApi="User_List"
-      layout="total, prev, pager, next"
-      :onResize="onResize"
-    >
-      <template #table-header>
-        <el-row :gutter="20">
-          <el-col :span="24" class="d-flex">
-            <span class="inline-flex">账户查询:</span>
-            <el-input v-model="search" type="text" />
-            <el-button type="primary" @click="searchHandle">搜索</el-button>
-          </el-col>
-        </el-row>
-      </template>
-      <template #T_name="{ row }">
-        <el-button type="primary" link @click="getApproverInfo(row)">{{ row.T_name }}</el-button>
+  <div>
+    <Drawer ref="drawerRef" :handleClose="callbackDrawer">
+      <template #header="{ params }">
+        <h3 :id="params.titleId" :class="params.titleClass">选择经办人</h3>
       </template>
-    </TableBase>
-  </Dialog>
+      <TableBase
+        ref="tableRef"
+        :columns="Dialogcolumns"
+        :initParam="InitParam"
+        :requestApi="User_List"
+        layout="total, prev, pager, next"
+        :onResize="onResize"
+      >
+        <template #table-header>
+          <el-row :gutter="20">
+            <el-col :span="24" class="d-flex">
+              <span class="inline-flex">姓名:</span>
+              <el-input v-model="search" type="text" placeholder="按姓名搜索" />
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+          </el-row>
+        </template>
+        <template #T_name="{ row }">
+          <el-button type="primary" link @click="getApproverInfo(row)">{{ row.T_name }}</el-button>
+        </template>
+      </TableBase>
+    </Drawer>
+  </div>
 </template>
 
 <style scoped>

+ 2 - 0
src/views/storehouse/sales/ContractDetail.vue

@@ -135,6 +135,8 @@ onUnmounted(() => {
                       v-if="item.prop === 'T_product_img'"
                       style="height: 50px"
                       :src="row.T_product_img"
+                      :preview-src-list="[row.T_product_img]"
+                      :preview-teleported="true"
                       fit="cover"
                     />
                     <el-tooltip

+ 52 - 29
src/views/workAttendance/RecordsFinance.vue

@@ -7,15 +7,16 @@ import TableBase from '@/components/TableBase/index.vue'
 import type { FormInstance, FormRules } from 'element-plus'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { ColumnProps } from '@/components/TableBase/interface/index'
-import Pagination from '@/components/TableBase/components/Pagination.vue'
+// import Pagination from '@/components/TableBase/components/Pagination.vue'
 import { ref, reactive, onMounted, computed, onUnmounted, nextTick } from 'vue'
 import { Leave_Finance_List, Leave_Deduct, LeaveType_List } from '@/api/workAttendance/index'
 
-const TableData = ref()
+// const TableData = ref()
 const LeaveType = ref<any[]>([])
 const globalStore = GlobalStore()
 const ruleFormRef = ref<FormInstance>()
-const initParam = { User_tokey: globalStore.GET_User_tokey }
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const initParam = reactive({ User_tokey: globalStore.GET_User_tokey, T_name: '' })
 const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
 const LeaveTableRef = ref<InstanceType<typeof TableBase> | null>(null)
 
@@ -30,7 +31,7 @@ const salaryFromData = ref({
 
 // 搜索以及参数
 const columns: ColumnProps[] = [
-  { prop: 'T_name', label: '姓名', name: 'T_name' },
+  { prop: 'T_name', label: '姓名' },
   { prop: 'T_post_name', label: '职位', ellipsis: true }
 ]
 const userColums: ColumnProps[] = [
@@ -87,30 +88,30 @@ const onResize = () => {
   return height - 140 - 74 - 60 - 4 * 12
 }
 
-const getTableData = async () => {
-  const res: any = await User_List({ ...initParam })
-  TableData.value = res.Data.Data
-  pageable.total = res.Data.Num
-}
-onMounted(async () => {
-  await getTableData()
-})
-const pageable = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  total: 0,
-  small: false,
-  disabled: false
-})
-const handleSizeChange = (val: number) => {
-  pageable.pageSize = val
-  LeaveTableRef.value?.getTableList()
-}
+// const getTableData = async () => {
+//   const res: any = await User_List({ ...initParam })
+//   TableData.value = res.Data.Data
+//   pageable.total = res.Data.Num
+// }
+// onMounted(async () => {
+//   await getTableData()
+// })
+// const pageable = reactive({
+//   pageNum: 1,
+//   pageSize: 10,
+//   total: 0,
+//   small: false,
+//   disabled: false
+// })
+// const handleSizeChange = (val: number) => {
+//   pageable.pageSize = val
+//   LeaveTableRef.value?.getTableList()
+// }
 
-const handleCurrentChange = (val: number) => {
-  pageable.pageNum = val
-  LeaveTableRef.value?.getTableList()
-}
+// const handleCurrentChange = (val: number) => {
+//   pageable.pageNum = val
+//   LeaveTableRef.value?.getTableList()
+// }
 let clientHeight = ref(0)
 const onContentResize = () => {
   const height = document.documentElement.clientHeight
@@ -224,11 +225,12 @@ const open = () => {
       ElMessage.info('取消成功!')
     })
 }
+const searchHandle = () => TableRef.value?.searchTable()
 </script>
 
 <template>
   <div class="RecordsFinance">
-    <div style="width: 290px; display: flex; padding: 20px; background: #fff; flex-direction: column">
+    <!-- <div style="width: 290px; display: flex; padding: 20px; background: #fff; flex-direction: column">
       <el-table
         class="h-100"
         style="width: 100%; height: 100%; flex: 1"
@@ -250,6 +252,27 @@ const open = () => {
         :handleSizeChange="handleSizeChange"
         :handleCurrentChange="handleCurrentChange"
       />
+    </div> -->
+    <div style="width: 290px">
+      <TableBase
+        ref="TableRef"
+        :columns="columns"
+        :requestApi="User_List"
+        :initParam="initParam"
+        layout="prev, pager, next"
+        :rowClick="getSalaryParams"
+        :tableRowClassName="tableRowClassName"
+      >
+        <template #table-header>
+          <el-row :gutter="24" class="input-suffix margin-left-0 margin-right-0">
+            <el-col :span="24" class="d-flex padding-right-0 padding-left-0">
+              <span class="inline-flex">姓名:</span>
+              <el-input type="text" v-model="initParam.T_name" @change="searchHandle" />
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+          </el-row>
+        </template>
+      </TableBase>
     </div>
     <transition
       leave-active-class="animate__animated animate__bounceOutRight"
@@ -260,7 +283,7 @@ const open = () => {
           <el-card class="m-b-3">
             <h3 class="title m-b-5">员工基本信息</h3>
             <div class="info-content">
-              <el-avatar shape="square" size="large" :src="userInfo.squareUrl" />
+              <el-avatar shape="square" size="large"><img src="@/assets/images/avatar.jpg" /> </el-avatar>
               <div class="info-name">
                 <h4 class="m-b-3">名字:{{ userInfo.name }}</h4>
                 <h4>

+ 57 - 31
src/views/workAttendance/records/Records.vue

@@ -10,7 +10,7 @@ import { ColumnProps } from '@/components/TableBase/interface/index'
 import { Leave_User_list, Overtime_User_list, Overtime_Stat } from '@/api/workAttendance/index'
 
 let clientHeight = ref(0)
-const TableData = ref([])
+// const TableData = ref([])
 const globalStore = GlobalStore()
 const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
 const leaveRef = ref<InstanceType<typeof TableBase> | null>(null)
@@ -19,7 +19,7 @@ const remainingTimeRef = ref<InstanceType<typeof TableBase> | null>(null)
 const drawerLeaveRef = ref<InstanceType<typeof Drawer> | null>(null)
 const drawerOvertimeRef = ref<InstanceType<typeof Drawer> | null>(null)
 
-const columns: ColumnProps[] = [{ prop: 'T_name', label: '姓名', name: 'T_name' }]
+const columns: ColumnProps[] = [{ prop: 'T_name', label: '姓名' }]
 const overtimeColums: ColumnProps[] = [
   { prop: 'T_start_time', label: '开始时间', ellipsis: true },
   { prop: 'T_end_time', label: '结束时间', ellipsis: true },
@@ -46,11 +46,11 @@ const leaveColums: ColumnProps[] = [
   { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
 ]
 
-const initParam = {
+const initParam = reactive({
   User_tokey: globalStore.GET_User_tokey,
   T_name: '',
   T_dept: ''
-}
+})
 const userInitParam = reactive({
   User_tokey: globalStore.GET_User_tokey,
   T_uuid: ''
@@ -106,33 +106,33 @@ const getSalaryParams = (row: any) => {
   remainingTimeRef.value && remainingTimeRef.value.searchTable()
 }
 // 获取数据
-const getTableData = async () => {
-  const res: any = await User_List({ ...initParam })
-  TableData.value = res.Data.Data
-  pageable.total = res.Data.Num
-}
+// const getTableData = async () => {
+//   const res: any = await User_List({ ...initParam })
+//   TableData.value = res.Data.Data
+//   pageable.total = res.Data.Num
+// }
 
-onMounted(async () => {
-  await getTableData()
-  // let userInfoFirst: any = TableData.value[0]
-  // userInfoAssign(userInfoFirst)
-})
+// onMounted(async () => {
+//   await getTableData()
+//   // let userInfoFirst: any = TableData.value[0]
+//   // userInfoAssign(userInfoFirst)
+// })
 // 分页
-const pageable = reactive({
-  pageNum: 1,
-  pageSize: 10,
-  total: 0,
-  small: false,
-  disabled: false
-})
-const handleSizeChange = (val: number) => {
-  pageable.pageSize = val
-  TableRef.value && TableRef.value.getTableList()
-}
-const handleCurrentChange = (val: number) => {
-  pageable.pageNum = val
-  TableRef.value && TableRef.value.getTableList()
-}
+// const pageable = reactive({
+//   pageNum: 1,
+//   pageSize: 10,
+//   total: 0,
+//   small: false,
+//   disabled: false
+// })
+// const handleSizeChange = (val: number) => {
+//   pageable.pageSize = val
+//   TableRef.value && TableRef.value.getTableList()
+// }
+// const handleCurrentChange = (val: number) => {
+//   pageable.pageNum = val
+//   TableRef.value && TableRef.value.getTableList()
+// }
 // 查看加班记录
 const viewOvertime = (row: any) => {
   url = row.T_prove_img
@@ -177,11 +177,13 @@ const tableRowClassName = (data: any): any => {
     return ''
   }
 }
+
+const searchHandle = () => TableRef.value?.searchTable()
 </script>
 
 <template>
   <div class="records">
-    <div class="userTable">
+    <!-- <div class="userTable">
       <el-table
         ref="TableRef"
         class="h-100"
@@ -199,11 +201,35 @@ const tableRowClassName = (data: any): any => {
         />
       </el-table>
       <Pagination
+        small
+        :pager-count="3"
         layout="total, prev, pager, next"
         :pageable="pageable"
         :handleSizeChange="handleSizeChange"
         :handleCurrentChange="handleCurrentChange"
       />
+    </div> -->
+    <div style="width: 290px">
+      <TableBase
+        ref="TableRef"
+        :columns="columns"
+        :requestApi="User_List"
+        :initParam="initParam"
+        layout="prev, pager, next"
+        :rowClick="getSalaryParams"
+        :tableRowClassName="tableRowClassName"
+      >
+        <template #table-header>
+          <!-- <h3 class="title">待处理</h3> -->
+          <el-row :gutter="24" class="input-suffix margin-left-0 margin-right-0">
+            <el-col :span="24" class="d-flex padding-right-0 padding-left-0">
+              <span class="inline-flex">姓名:</span>
+              <el-input type="text" v-model="initParam.T_name" @change="searchHandle" />
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+          </el-row>
+        </template>
+      </TableBase>
     </div>
     <transition
       leave-active-class="animate__animated animate__bounceOutRight"
@@ -214,7 +240,7 @@ const tableRowClassName = (data: any): any => {
           <el-card class="m-b-3">
             <h3 class="title m-b-5">员工基本信息</h3>
             <div class="info-content">
-              <el-avatar shape="square" size="large" :src="userInfo.squareUrl" />
+              <el-avatar shape="square" size="large"><img src="@/assets/images/avatar.jpg" /> </el-avatar>
               <div class="info-name">
                 <h4 class="m-b-3">名字:{{ userInfo.name }}</h4>
                 <h4>

+ 14 - 4
src/views/workAttendance/records/index.scss

@@ -2,9 +2,15 @@
   display: flex;
   height: 100%;
   overflow: hidden;
-  :deep(.table-header) {
-    border: none;
-    padding: 0;
+  .inline-flex {
+    white-space: nowrap;
+    display: inline-flex;
+  }
+  .d-flex {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    flex-wrap: nowrap;
   }
   .btn {
     margin-top: 2rem;
@@ -20,13 +26,17 @@
   }
   .title {
     width: 100%;
-    text-align: left;
+    // text-align: left;
   }
   .content {
     width: 99.9%;
     height: 700px;
     background: #fff;
     overflow-y: auto;
+    :deep(.table-header) {
+      border: none;
+      padding: 0;
+    }
     .content-table-item {
       padding: 20px;
       .font-large {

+ 16 - 16
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(),