zoie 2 сар өмнө
parent
commit
962dbca269
28 өөрчлөгдсөн 3876 нэмэгдсэн , 531 устгасан
  1. 33 10
      src/api/storehouse/index.ts
  2. 4 1
      src/components/Drawer/index.vue
  3. 29 3
      src/hooks/useDepot.ts
  4. 10 0
      src/hooks/useTablePublic.ts
  5. 17 1
      src/router/modules/staticRouter.ts
  6. 311 292
      src/views/storehouse/InventoryStatistics.vue
  7. 9 4
      src/views/storehouse/inventory/InStorageEditSn.vue
  8. 10 4
      src/views/storehouse/inventory/InStorageSn.vue
  9. 262 200
      src/views/storehouse/outStock/OutStockDetail.vue
  10. 5 0
      src/views/storehouse/outStock/OutStockProduct.vue
  11. 1 1
      src/views/storehouse/outStock/ReceiveOutStock.vue
  12. 2 0
      src/views/storehouse/outStock/modules/InStorageEdit.vue
  13. 10 4
      src/views/storehouse/outStock/modules/InStorageEditSn.vue
  14. 250 0
      src/views/storehouse/outStock/outStockApply/OutStockApply.vue
  15. 189 0
      src/views/storehouse/outStock/outStockApply/OutStockApplyFinance.vue
  16. 189 0
      src/views/storehouse/outStock/outStockApply/OutStockApplyManager.vue
  17. 233 0
      src/views/storehouse/outStock/outStockApply/OutStockApplyWarehouse.vue
  18. 293 0
      src/views/storehouse/outStock/outStockApply/OutStockAudit.vue
  19. 279 0
      src/views/storehouse/outStock/outStockApply/OutStockProduct.vue
  20. 277 0
      src/views/storehouse/outStock/outStockApply/ReceiveOutStockApply.vue
  21. 366 0
      src/views/storehouse/outStock/outStockApply/modules/OutStorageEdit.vue
  22. 238 0
      src/views/storehouse/outStock/outStockApply/modules/OutStorageEditSn.vue
  23. 356 0
      src/views/storehouse/outStock/outStockApply/modules/OutStorageProduct.vue
  24. 395 0
      src/views/storehouse/outStock/outStockApply/modules/OutStorageWarehouse.vue
  25. 7 0
      src/views/storehouse/sales/ContractDetail.vue
  26. 8 0
      src/views/storehouse/sales/VerifyContractDetail.vue
  27. 30 3
      src/views/storehouse/sales/VerifyForm.vue
  28. 63 8
      src/views/storehouse/verifyCompany/VerifyContract.vue

+ 33 - 10
src/api/storehouse/index.ts

@@ -104,7 +104,7 @@ export const Storehouse_Contract_Edit = (params: any) => $http.post('/storage/Co
 export const Storehouse_Contract_Del = (params: any) => $http.post('/storage/Contract/Del', params)
 // 产品列表
 export const Storehouse_Contract_Product_List = (params: any) =>
-  $http.post('/storage/Contract/Product_List', params)
+	$http.post('/storage/Contract/Product_List', params)
 // 获取为出库或为完全出库合同列表
 export const Storehouse_Contract_Out_List = (params: any) => $http.post('/storage/Contract/Out_List', params)
 // 打款
@@ -123,13 +123,13 @@ export const validation_Stat = (params: any) => $http.post('/storage/validationT
 export const validation_add = (params: any) => $http.post('/storage/validationTool/add', params)  //借出验证工具
 export const validation_del = (params: any) => $http.post('/storage/validationTool/del', params,)
 export const validation_update = (params: any) => $http.post('/storage/validationTool/update', params,)  //借出验证工具
-export const validation_scrap= (params: any) => $http.post('/storage/validationTool/scrap', params)  //报废验证工具
-export const validation_repair= (params: any) => $http.post('/storage/validationTool/repair', params)  //维修验证工具
+export const validation_scrap = (params: any) => $http.post('/storage/validationTool/scrap', params)  //报废验证工具
+export const validation_repair = (params: any) => $http.post('/storage/validationTool/repair', params)  //维修验证工具
 export const readValidation = (params: any) => $http.post('/storage/validationTool/readValidation', params,)
 export const updateValidation = (params: any) => $http.post('/storage/validationTool/updateValidation', params,)
 export const uploadFile = (params: any) => $http.post('/storage/validationTool/ImportExcel', params,)
-export const exportFile = (params: any) => $http.post('/storage/validationTool/exportExcel', params, { responseType: 'blob' })
-export const exportOperationFile = (params: any) => $http.post('/storage/validationTool/exportOperationExcel', params, { responseType: 'blob' })
+export const exportFile = (params: any) => $http.post('/storage/validationTool/exportExcel', params, {responseType: 'blob'})
+export const exportOperationFile = (params: any) => $http.post('/storage/validationTool/exportOperationExcel', params, {responseType: 'blob'})
 // 左侧用户列表
 export const validation_User_List = (params: any) => $http.post('/storage/validationTool/user/list', params)
 export const validationTool_class_list = (params: any) => $http.post('/storage/validationTool/class/list', params)
@@ -171,6 +171,27 @@ export const Storehouse_StockOut_Del = (params: any) => $http.post('/storage/Sto
 // 修改发货订单
 export const Storehouse_StockOut_Edit = (params: any) => $http.post('/storage/StockOut/Edit_Delivery', params)
 
+
+/**
+ * 出库申请
+ */
+// 出库列表
+export const Storehouse_StockOut_Apply_List = (params: any) => $http.post('/storage/StockOut/Apply_List', params)
+// 出库申请
+export const Storehouse_StockOut_Apply = (params: any) => $http.post('/storage/StockOut/Apply', params)
+export const Storehouse_StockOut_Apply_Edit = (params: any) => $http.post('/storage/StockOut/Apply_Edit', params)
+export const Storehouse_StockOut_Apply_Del = (params: any) => $http.post('/storage/StockOut/Apply_Del', params)
+// 财务列表
+export const Storehouse_StockOut_Finance_List = (params: any) => $http.post('/storage/StockOut/Finance_List', params)
+// 管理员列表
+export const Storehouse_StockOut_Manager_List = (params: any) => $http.post('/storage/StockOut/Manager_List', params)
+// 仓管列表
+export const Storehouse_StockOut_Warehouse_List = (params: any) => $http.post('/storage/StockOut/Warehouse_List', params)
+// 出库审核
+export const Storehouse_StockOut_Audit = (params: any) => $http.post('/storage/StockOut/Audit', params)
+// 确认出库
+export const Storehouse_StockOut_Warehouse = (params: any) => $http.post('/storage/StockOut/Warehouse', params)
+
 /**
  * 库存统计
  */
@@ -189,13 +210,13 @@ export const Storehouse_Device_Check = (params: any) => $http.post('/storage/Dev
  */
 // 客户列表
 export const Storehouse_VerifyContract_Customer_List = (params: any) =>
-  $http.post('/storage/VerifyContract/Customer_List', params)
+	$http.post('/storage/VerifyContract/Customer_List', params)
 // 添加客户
 export const Storehouse_VerifyContract_Add_Customer = (params: any) =>
-  $http.post('/storage/VerifyContract/Add_Customer', params)
+	$http.post('/storage/VerifyContract/Add_Customer', params)
 // 编辑客户
 export const Storehouse_VerifyContract_Update_Customer = (params: any) =>
-  $http.post('/storage/VerifyContract/Update_Customer', params)
+	$http.post('/storage/VerifyContract/Update_Customer', params)
 // 明细列表
 export const Storehouse_VerifyContract_List = (params: any) => $http.post('/storage/VerifyContract/List', params)
 // 添加
@@ -206,13 +227,15 @@ export const Storehouse_VerifyContract_Edit = (params: any) => $http.post('/stor
 export const Storehouse_VerifyContract_Get = (params: any) => $http.post('/storage/VerifyContract/Get', params)
 // 删除
 export const Storehouse_VerifyContract_Del = (params: any) => $http.post('/storage/VerifyContract/Del', params)
+// 导出excel
+export const Storehouse_VerifyContract_Excel = (params: any) => $http.post('/storage/VerifyContract/Excel', params, {responseType: 'blob'})
 
 /**
  * 回款管理
  */
 //回款列表
 export const Storehouse_VerifyContract_Recover_List = (params: any) =>
-  $http.post('/storage/RecoveriesContract/List', params)
+	$http.post('/storage/RecoveriesContract/List', params)
 export const Storehouse_VerifyContract_Recover_User_List = (params: any) =>
 	$http.post('/storage/RecoveriesContract/User/List', params)
 //导出
@@ -235,5 +258,5 @@ export const Storehouse_IOTNetworkCard_Add = (params: any) => $http.post('/stora
 export const Storehouse_IOTNetworkCard_Edit = (params: any) => $http.post('/storage/IOTNetworkCard/Edit', params)
 export const Storehouse_IOTNetworkCard_Del = (params: any) => $http.post('/storage/IOTNetworkCard/Del', params)
 export const Storehouse_IOTNetworkCard_Import = (params: any) => $http.post('/storage/IOTNetworkCard/Import', params)
-export const Storehouse_IOTNetworkCard_Export = (params: any) => $http.post('/storage/IOTNetworkCard/Export', params, { responseType: 'blob' })
+export const Storehouse_IOTNetworkCard_Export = (params: any) => $http.post('/storage/IOTNetworkCard/Export', params, {responseType: 'blob'})
 export const Storehouse_IOTNetworkCard_Edit_Device_Number = (params: any) => $http.post('/storage/IOTNetworkCard/Edit_Device_Number', params)

+ 4 - 1
src/components/Drawer/index.vue

@@ -7,6 +7,7 @@ type Fn = () => void
 interface drawerProps {
   title?: string
   size?: string
+	closeModal?: boolean
   handleClose?: (params: Fn) => void
   openDrawer?: (params: Fn) => void
 	openValidation?: (params: Fn) => void
@@ -15,6 +16,7 @@ interface drawerProps {
 
 withDefaults(defineProps<drawerProps>(), {
   title: '',
+	closeModal: true,
   size: '30%',
   direction: 'rtl' // rtl / ltr / ttb / btt
 })
@@ -35,7 +37,8 @@ defineExpose({ closeDrawer, openDrawer })
       :direction="direction"
       :size="size"
       :destroy-on-close="true"
-    >
+	  :close-on-click-modal="closeModal"
+	>
       <template #header="{ close, titleId, titleClass }">
         <div class="header">
           <slot name="header" :params="{ close, titleId, titleClass }"></slot>

+ 29 - 3
src/hooks/useDepot.ts

@@ -38,6 +38,17 @@ export interface ReceiveFormType {
   T_contract_number: string
 }
 
+export interface ReceiveApplyFormType {
+	T_project:string
+	T_number: string
+	T_depot_id: any
+	T_product: any
+	T_remark: string
+	T_contract_number: string
+	T_company_name: string
+	T_payment_method: string
+}
+
 export interface InfoType {
   Id: number
   T_type: number
@@ -52,9 +63,16 @@ export interface InfoType {
   T_signer_unit?: string
   T_submit_name: string
   T_receive_name: string
+  T_warehouse_name: string
   T_project: string
   T_delivery_type: string
   T_courier_number?: number
+  T_company_name: string
+  T_payment_method: string
+  T_state_str: string
+  T_application_date: string
+  T_finance_approval_opinion: string
+  T_manager_approval_opinion: string
 }
 
 export interface InStorageInfoType {
@@ -83,12 +101,20 @@ export interface InStoreageFormTypes {
     T_product: any
     T_project: any
     T_date: string
+    T_receive: string
+    T_receive_name: string
     T_remark: string
-    T_receive:string
-    T_receive_name:string
-
+    T_company_name: string
+    T_payment_method: string
   }
 
+export interface OutStockAuditFormType {
+	T_number: string
+	T_audit: number
+	T_approval_opinion: string
+	T_type: string
+}
+
 export const delivery_type = [
   { name: '自送', id: 1 },
   { name: '自提', id: 2 },

+ 10 - 0
src/hooks/useTablePublic.ts

@@ -41,6 +41,8 @@ export interface ContractFormType {
 	T_customer?: string
 	T_start_date?: string
 	T_end_date?: string
+	T_stamping_date?: string
+	T_payment_method?: string
 	T_date: string
 	T_project?: string
 	T_remark: string
@@ -225,6 +227,14 @@ export const deptOptions = [
 	{name: '销售部', id: '销售部'},
 ]
 
+
+export const paymentMethodOptions = [
+	{name: '先款后货', id: 'A'},
+	{name: '收部分定金50%', id: 'B'},
+	{name: '先货后款', id: 'C'},
+	{name: '项目支持', id: 'D'},
+]
+
 export function useStapublicFun(data: any) {
 	const a = options2.find((item: any) => item.id == data)
 	return a?.name

+ 17 - 1
src/router/modules/staticRouter.ts

@@ -99,6 +99,14 @@ export const staticRouter: RouteRecordRaw[] = [
               title: '领料出库'
             }
           },
+			{
+				path: '/receiveOutStockApply',
+				name: 'receiveOutStockApply',
+				component: () => import('@/views/storehouse/outStock/OutStockApply/receiveOutStockApply.vue'),
+				meta: {
+					title: '出库申请'
+				}
+			},
           {
             path: '/saleOutStock',
             name: 'SaleOutStock',
@@ -114,7 +122,15 @@ export const staticRouter: RouteRecordRaw[] = [
             meta: {
               title: '出库详情'
             }
-          }
+          },
+		{
+			path: '/OutStockAudit/:number/:type',
+			name: 'OutStockAudit',
+			component: () => import('@/views/storehouse/outStock/outStockApply/OutStockAudit.vue'),
+			meta: {
+				title: '出库审批'
+			}
+		}
         ]
       },
       {

+ 311 - 292
src/views/storehouse/InventoryStatistics.vue

@@ -1,89 +1,90 @@
 <script setup lang="ts">
 import {
-    Storehouse_Stock_List,
-    Storehouse_Depot_List,
-    Storehouse_ProductClass_List,
-    Storehouse_Product_Model_List,
-    Storehouse_Product_Name_List,
-    Storehouse_Stock_Detail_List,
-    Storehouse_Stock_Detail_Excel,
-    stockInSort
+	stockInSort,
+	Storehouse_Depot_List,
+	Storehouse_Product_Model_List,
+	Storehouse_Product_Name_List,
+	Storehouse_ProductClass_List,
+	Storehouse_Stock_Detail_Excel,
+	Storehouse_Stock_Detail_List,
+	Storehouse_Stock_List
 } from '@/api/storehouse/index'
-import { ref, reactive, onMounted } from 'vue'
-import { List } from '@element-plus/icons-vue'
+import {onMounted, reactive, ref} from 'vue'
+import {List} from '@element-plus/icons-vue'
 import Drawer from '@/components/Drawer/index.vue'
-import { GlobalStore } from '@/stores/index'
+import {GlobalStore} from '@/stores/index'
 import TableBase from '@/components/TableBase/index.vue'
-import type { ColumnProps } from '@/components/TableBase/interface/index'
-import { dayJs } from '@/utils/common'
+import type {ColumnProps} from '@/components/TableBase/interface/index'
+import {dayJs} from '@/utils/common'
 import ImageCom from '@/components/Image/index.vue'
-import { useTablePublic } from '@/hooks/useTablePublic'
-import { ElMessage, ElMessageBox } from 'element-plus'
+import {useTablePublic} from '@/hooks/useTablePublic'
+import {ElMessage, ElMessageBox} from 'element-plus'
 import InventoryStatisticsshowModel from "./modules/InventoryStatisticsshowModel.vue";
 
 
 const userInfo = ref({
-    Id: '',
-    T_name: ''
+	Id: '',
+	T_name: ''
 })
 const loading = ref(false)
 const globalStore = GlobalStore()
 const DrawerRef = ref<InstanceType<typeof Drawer> | null>(null)
 const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
 const TableDetailRef = ref<InstanceType<typeof TableBase> | null>(null)
-const { tableRowClassName } = useTablePublic()
+const {tableRowClassName} = useTablePublic()
 const tableRowClassNameHandle = (data: any): any => tableRowClassName(data.row.Id, userInfo.value.Id)
 
 const initParam = reactive({
-    User_tokey: globalStore.GET_User_tokey,
-    T_depot_id: '',
-    T_product_class: '',
-    T_product_name: '',
-    T_product_model: ''
+	User_tokey: globalStore.GET_User_tokey,
+	T_depot_id: '',
+	T_product_class: '',
+	T_product_name: '',
+	T_product_model: ''
 })
 const detailInitParam = reactive({
-    T_depot_id: '',
-    T_product_id: '',
-    T_start_date: '',
-    T_end_date: ''
+	T_depot_id: '',
+	T_product_id: '',
+	T_start_date: '',
+	T_end_date: ''
 })
 const columns: ColumnProps[] = [
-    { type: 'index', label: '序号', width: 80 },
-    { prop: 'T_depot_name', label: '仓库名称' },
-    { prop: 'T_sort', label: '排序(双击排序)', name: 'T_sort' },
-    { prop: 'T_product_img', label: '产品图片', name: 'T_product_img' },
-    { prop: 'T_product_name', label: '产品名称' },
-    { prop: 'T_product_class_name', label: '产品分类' },
-    { prop: 'T_product_model', label: '产品型号', ellipsis: true },
-    { prop: 'T_product_spec', label: '产品规格' },
-    { prop: 'T_total', label: '库存数量', name: 'T_total'},
-    { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_depot_name', label: '仓库名称'},
+	{prop: 'T_sort', label: '排序(双击排序)', name: 'T_sort'},
+	{prop: 'T_product_img', label: '产品图片', name: 'T_product_img'},
+	{prop: 'T_product_name', label: '产品名称'},
+	{prop: 'T_product_class_name', label: '产品分类'},
+	{prop: 'T_product_model', label: '产品型号', ellipsis: true},
+	{prop: 'T_product_spec', label: '产品规格'},
+	{prop: 'T_total', label: '库存数量', name: 'T_total'},
+	{prop: 'T_occupy', label: '占用库存', name: 'T_occupy'},
+	{prop: 'operation', label: '操作', width: 80, fixed: 'right'}
 ]
 
 const detailColumns: ColumnProps[] = [
-    { type: 'index', label: '序号', width: 80 },
-    { prop: 'T_product_name', label: '产品名称' },
-    { prop: 'T_product_model', label: '产品型号', ellipsis: true },
-    { prop: 'T_product_spec', label: '产品规格' },
-    { prop: 'T_month', label: '月份' },
-    { prop: 'T_beginning', label: '期初库存' },
-    { prop: 'T_in', label: '入库' },
-    { prop: 'T_out', label: '出库' },
-    { prop: 'T_ending', label: '期末库存' },
-    { prop: 'operation', label: '关联项目', width: 200, fixed: 'right' }
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_product_name', label: '产品名称'},
+	{prop: 'T_product_model', label: '产品型号', ellipsis: true},
+	{prop: 'T_product_spec', label: '产品规格'},
+	{prop: 'T_month', label: '月份'},
+	{prop: 'T_beginning', label: '期初库存'},
+	{prop: 'T_in', label: '入库'},
+	{prop: 'T_out', label: '出库'},
+	{prop: 'T_ending', label: '期末库存'},
+	{prop: 'operation', label: '关联项目', width: 200, fixed: 'right'}
 ]
 
 const searchHandle = () => {
-    TableRef.value?.searchTable()
+	TableRef.value?.searchTable()
 }
 const dataCallback = (res: any) => {
-    let arr = res.Data.Data || []
-    return arr.map((item: any) => {
-        if (item.T_depot_id === userInfo.value.Id) {
-            item.T_depot_name = userInfo.value.T_name
-        }
-        return item
-    })
+	let arr = res.Data.Data || []
+	return arr.map((item: any) => {
+		if (item.T_depot_id === userInfo.value.Id) {
+			item.T_depot_name = userInfo.value.T_name
+		}
+		return item
+	})
 }
 const detailDataCallback = (res: any) => res.Data
 /**
@@ -95,124 +96,125 @@ const visible = ref(false)
 const exportExcel = () => (visible.value = true)
 const confirmExpor = async (project_id?: string) => {
 
-    const params = {
-        User_tokey: globalStore.GET_User_tokey,
-        T_depot_id: initParam.T_depot_id,
-        T_start_date: T_date_detail.value[0],
-        T_end_date: T_date_detail.value[1],
-        T_product_id: ''
-    }
-    console.log('导出', T_date_detail.value, params)
-    if (typeof project_id === 'number') {
-        params['T_product_id'] = project_id
-    }
-    const res: any = await Storehouse_Stock_Detail_Excel(params)
-    if (res.Code === 200) {
-        window.open(res.Data)
-    }
+	const params = {
+		User_tokey: globalStore.GET_User_tokey,
+		T_depot_id: initParam.T_depot_id,
+		T_start_date: T_date_detail.value[0],
+		T_end_date: T_date_detail.value[1],
+		T_product_id: ''
+	}
+	console.log('导出', T_date_detail.value, params)
+	if (typeof project_id === 'number') {
+		params['T_product_id'] = project_id
+	}
+	const res: any = await Storehouse_Stock_Detail_Excel(params)
+	if (res.Code === 200) {
+		window.open(res.Data)
+	}
 }
 const NameOptions = ref<any[]>([])
 const classOptions = ref<any[]>([])
 const modelOptions = ref<any[]>([])
 // 获取产品分类
 const getProductClassList = async () => {
-    const res: any = await Storehouse_ProductClass_List({ page: 1, page_z: 999 })
-    classOptions.value = res.Data.Data
+	const res: any = await Storehouse_ProductClass_List({page: 1, page_z: 999})
+	classOptions.value = res.Data.Data
 }
 /**
  * 模糊搜索名称
  * @param str 名称字符串
  */
 const getNameAsync = async (str: string): Promise<any> => {
-    const res: any = await Storehouse_Product_Name_List({ T_name: str, T_class: initParam.T_product_class })
-    if (!res.Data) return
-    return res.Data.map((item: any, index: number) => {
-        return {
-            value: item,
-            index: index
-        }
-    })
+	const res: any = await Storehouse_Product_Name_List({T_name: str, T_class: initParam.T_product_class})
+	if (!res.Data) return
+	return res.Data.map((item: any, index: number) => {
+		return {
+			value: item,
+			index: index
+		}
+	})
 }
 /**
  * 模糊搜索名称
  * @param queryString 输入框的输入字符
  */
 const querySearchAsync = async (queryString: string) => {
-    if (queryString) {
-        loading.value = true
-        globalStore.SET_isloading(true)
-        const results = await getNameAsync(queryString)
-        NameOptions.value = results
-        globalStore.SET_isloading(false)
-        loading.value = false
-    }
+	if (queryString) {
+		loading.value = true
+		globalStore.SET_isloading(true)
+		const results = await getNameAsync(queryString)
+		NameOptions.value = results
+		globalStore.SET_isloading(false)
+		loading.value = false
+	}
 }
 /**
  * 异步获取产品型号
  */
 const getProductModelList = async () => {
-    globalStore.SET_isloading(true)
-    const res: any = await Storehouse_Product_Model_List({ T_name: initParam.T_product_name })
-    modelOptions.value = res.Data.map((item: any, index: number) => {
-        return {
-            value: item,
-            index: index
-        }
-    })
-    globalStore.SET_isloading(false)
+	globalStore.SET_isloading(true)
+	const res: any = await Storehouse_Product_Model_List({T_name: initParam.T_product_name})
+	modelOptions.value = res.Data.map((item: any, index: number) => {
+		return {
+			value: item,
+			index: index
+		}
+	})
+	globalStore.SET_isloading(false)
 }
 const handleSelect = (item: any) => {
-    initParam.T_product_name = item.value
-    getProductModelList()
+	initParam.T_product_name = item.value
+	getProductModelList()
 }
 
 // 明细
 const callbackDrawer = (done: () => void) => done()
 const previewDetail = (id: string) => {
-    DrawerRef.value?.openDrawer()
-    T_date_detail.value = [...T_date.value]
-    if (detailInitParam.T_product_id === id) return
-    detailInitParam.T_depot_id = initParam.T_depot_id
-    detailInitParam.T_product_id = id
-    detailInitParam.T_start_date = T_date.value[0]
-    detailInitParam.T_end_date = T_date.value[1]
-    TableDetailRef.value?.searchTable()
+	DrawerRef.value?.openDrawer()
+	T_date_detail.value = [...T_date.value]
+	if (detailInitParam.T_product_id === id) return
+	detailInitParam.T_depot_id = initParam.T_depot_id
+	detailInitParam.T_product_id = id
+	detailInitParam.T_start_date = T_date.value[0]
+	detailInitParam.T_end_date = T_date.value[1]
+	TableDetailRef.value?.searchTable()
 }
 const dateDetailChange = (str: string[]) => {
-    if (!str) return
-    detailInitParam.T_start_date = str[0]
-    detailInitParam.T_end_date = str[1]
-    TableDetailRef.value?.searchTable()
+	if (!str) return
+	detailInitParam.T_start_date = str[0]
+	detailInitParam.T_end_date = str[1]
+	TableDetailRef.value?.searchTable()
 }
 onMounted(() => {
-    getProductClassList()
-    T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
-    T_date_detail.value = [...T_date.value]
-    console.log('初始化时间', T_date)
+	getProductClassList()
+	T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
+	T_date_detail.value = [...T_date.value]
+	console.log('初始化时间', T_date)
 })
 
 const getSalaryParams = (row: any) => {
-    userInfo.value.Id = ''
-    setTimeout(() => {
-        userInfo.value = { ...row }
-        initParam.T_depot_id = userInfo.value.Id
-    }, 100)
+	userInfo.value.Id = ''
+	setTimeout(() => {
+		userInfo.value = {...row}
+		initParam.T_depot_id = userInfo.value.Id
+	}, 100)
 }
 
-const handleHeaderClick = async (e:any) => {
-    ElMessageBox.prompt('请输入排序号', '', {
-        confirmButtonText: 'OK',
-        cancelButtonText: 'Cancel',
-        inputValue:`${e.T_sort}`
-    }).then(async({ value }) => {
-       const result:any = await stockInSort({T_id:e.Id,T_sort:value})
-       console.log('提交',value,result)
-       if(result.Code==200){
-            ElMessage.success('编辑成功')
-            TableRef.value?.getTableList()
-       }
+const handleHeaderClick = async (e: any) => {
+	ElMessageBox.prompt('请输入排序号', '', {
+		confirmButtonText: 'OK',
+		cancelButtonText: 'Cancel',
+		inputValue: `${e.T_sort}`
+	}).then(async ({value}) => {
+		const result: any = await stockInSort({T_id: e.Id, T_sort: value})
+		console.log('提交', value, result)
+		if (result.Code == 200) {
+			ElMessage.success('编辑成功')
+			TableRef.value?.getTableList()
+		}
 
-    }).catch(() => {})
+	}).catch(() => {
+	})
 
 }
 
@@ -220,190 +222,207 @@ const handleHeaderClick = async (e:any) => {
 </script>
 
 <template>
-    <div class="inventory-statistics">
-        <div style="width: 290px" class="inventory-table">
-            <TableBase ref="TableRef" :columns="[{ prop: 'T_name', label: '仓库名称' }]" :requestApi="Storehouse_Depot_List"
-                :initParam="{ User_tokey: globalStore.GET_User_tokey }" layout="prev, pager, next"
-                :rowClick="getSalaryParams" :tableRowClassName="tableRowClassNameHandle">
-                <template #table-header>
-                    <h3 class="title">仓库列表</h3>
-                </template>
-            </TableBase>
-        </div>
-        <transition leave-active-class="animate__animated animate__fadeOutRight"
-            enter-active-class="animate__animated animate__fadeInLeft">
-            <div class="project-container" v-if="userInfo.Id">
-                <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_Stock_List" :initParam="initParam"
-                    :dataCallback="dataCallback">
-                    <template #table-header>
-                        <div class="head-search active">
-                            <el-form :model="initParam" class="result-form" label-width="100px">
-                                <el-row>
-                                    <el-col :span="12"><el-form-item label="产品分类" :inline-message="true">
-                                            <el-select v-model="initParam.T_product_class" clearable
-                                                placeholder="请选择分类~" class="w-50">
-                                                <el-option v-for="item in classOptions" :key="item.Id"
-                                                    :label="item.T_name" :value="item.Id" />
-                                            </el-select> </el-form-item></el-col>
-                                    <el-col :span="12">
-                                        <el-form-item label="产品名称">
-                                            <el-input v-model="initParam.T_product_name" placeholder="请输入产品名称" />
-                                            <!-- <el-select v-model="initParam.T_product_name" filterable clearable remote
-                                                reserve-keyword placeholder="按产品名称搜索" remote-show-suffix
-                                                :remote-method="querySearchAsync" :loading="loading"
-                                                @change="handleSelect">
-                                                <el-option v-for="item in NameOptions" :key="item.value"
-                                                    :label="item.value" :value="item.value" />
-                                            </el-select>  -->
-                                        </el-form-item>
-                                    </el-col>
-                                </el-row>
-                                <el-row class="search-bottom">
-                                    <el-col :span="12">
-                                        <el-form-item label="产品型号">
-                                            <el-input v-model="initParam.T_product_model" placeholder="请输入产品型号" />
-                                            <!-- <el-select v-model="initParam.T_product_model" clearable
-                                                placeholder="请选择型号~" class="w-50">
-                                                <el-option v-for="item in modelOptions" :key="item.index"
-                                                    :label="item.value" :value="item.value" />
-                                            </el-select> -->
-                                        </el-form-item>
-                                    </el-col>
-                                    <el-col :span="6" :offset="6">
-                                        <el-button type="primary" @click="searchHandle">搜索</el-button>
-                                        <el-popover :visible="visible" placement="bottom" :width="400" trigger="click">
-                                            <template #reference>
-                                                <el-button type="success" @click="exportExcel">导出</el-button>
-                                            </template>
-                                            <el-date-picker v-model="T_date_detail" type="daterange" range-separator="~"
-                                                start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD"
-                                                value-format="YYYY-MM-DD" />
-                                            <div class="export-popover">
-                                                <el-button size="small" @click="visible = false">取消</el-button>
-                                                <el-button size="small" type="primary"
-                                                    @click="confirmExpor">确认</el-button>
-                                            </div>
-                                        </el-popover>
-                                    </el-col>
-                                </el-row>
-                            </el-form>
-                        </div>
-                    </template>
-                    <template #T_sort="{ row }">
-                        <div @dblclick="handleHeaderClick(row)" style="cursor: pointer;">
-                            {{ row.T_sort }}
-                        </div>
-                    </template>
-                    <template #T_product_img="{ row }">
-                        <ImageCom :src="row.T_product_img" />
-                    </template>
-                    <template #T_total="{ row }">
-						<el-text :type="row.T_total >= row.T_product_early_warning?'info':'danger'"> {{row.T_total}} </el-text>
-                    </template>
-                    <template #right="{ row }">
-                        <el-button link type="primary" size="small" :icon="List"
-                            @click="previewDetail(row.T_product_id)">明细</el-button>
-                    </template>
-                </TableBase>
-            </div>
-        </transition>
+	<div class="inventory-statistics">
+		<div style="width: 290px" class="inventory-table">
+			<TableBase ref="TableRef" :columns="[{ prop: 'T_name', label: '仓库名称' }]"
+					   :requestApi="Storehouse_Depot_List"
+					   :initParam="{ User_tokey: globalStore.GET_User_tokey }" layout="prev, pager, next"
+					   :rowClick="getSalaryParams" :tableRowClassName="tableRowClassNameHandle">
+				<template #table-header>
+					<h3 class="title">仓库列表</h3>
+				</template>
+			</TableBase>
+		</div>
+		<transition leave-active-class="animate__animated animate__fadeOutRight"
+					enter-active-class="animate__animated animate__fadeInLeft">
+			<div class="project-container" v-if="userInfo.Id">
+				<TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_Stock_List" :initParam="initParam"
+						   :dataCallback="dataCallback">
+					<template #table-header>
+						<div class="head-search active">
+							<el-form :model="initParam" class="result-form" label-width="100px">
+								<el-row>
+									<el-col :span="12">
+										<el-form-item label="产品分类" :inline-message="true">
+											<el-select v-model="initParam.T_product_class" clearable
+													   placeholder="请选择分类~" class="w-50">
+												<el-option v-for="item in classOptions" :key="item.Id"
+														   :label="item.T_name" :value="item.Id"/>
+											</el-select>
+										</el-form-item>
+									</el-col>
+									<el-col :span="12">
+										<el-form-item label="产品名称">
+											<el-input v-model="initParam.T_product_name" placeholder="请输入产品名称"/>
+											<!-- <el-select v-model="initParam.T_product_name" filterable clearable remote
+												reserve-keyword placeholder="按产品名称搜索" remote-show-suffix
+												:remote-method="querySearchAsync" :loading="loading"
+												@change="handleSelect">
+												<el-option v-for="item in NameOptions" :key="item.value"
+													:label="item.value" :value="item.value" />
+											</el-select>  -->
+										</el-form-item>
+									</el-col>
+								</el-row>
+								<el-row class="search-bottom">
+									<el-col :span="12">
+										<el-form-item label="产品型号">
+											<el-input v-model="initParam.T_product_model" placeholder="请输入产品型号"/>
+											<!-- <el-select v-model="initParam.T_product_model" clearable
+												placeholder="请选择型号~" class="w-50">
+												<el-option v-for="item in modelOptions" :key="item.index"
+													:label="item.value" :value="item.value" />
+											</el-select> -->
+										</el-form-item>
+									</el-col>
+									<el-col :span="6" :offset="6">
+										<el-button type="primary" @click="searchHandle">搜索</el-button>
+										<el-popover :visible="visible" placement="bottom" :width="400" trigger="click">
+											<template #reference>
+												<el-button type="success" @click="exportExcel">导出</el-button>
+											</template>
+											<el-date-picker v-model="T_date_detail" type="daterange" range-separator="~"
+															start-placeholder="开始时间" end-placeholder="结束时间"
+															format="YYYY-MM-DD"
+															value-format="YYYY-MM-DD"/>
+											<div class="export-popover">
+												<el-button size="small" @click="visible = false">取消</el-button>
+												<el-button size="small" type="primary"
+														   @click="confirmExpor">确认
+												</el-button>
+											</div>
+										</el-popover>
+									</el-col>
+								</el-row>
+							</el-form>
+						</div>
+					</template>
+					<template #T_sort="{ row }">
+						<div @dblclick="handleHeaderClick(row)" style="cursor: pointer;">
+							{{ row.T_sort }}
+						</div>
+					</template>
+					<template #T_product_img="{ row }">
+						<ImageCom :src="row.T_product_img"/>
+					</template>
+					<template #T_total="{ row }">
+						<el-text :type="row.T_total >= row.T_product_early_warning?'info':'danger'"> {{ row.T_total }}
+						</el-text>
+					</template>
+					<template #T_occupy="{ row }">
+						<el-text :type="row.T_occupy == 0?'info':'danger'"> {{ row.T_occupy }}
+						</el-text>
+					</template>
+					<template #right="{ row }">
+						<el-button link type="primary" size="small" :icon="List"
+								   @click="previewDetail(row.T_product_id)">明细
+						</el-button>
+					</template>
+				</TableBase>
+			</div>
+		</transition>
 
-        <Drawer ref="DrawerRef" :handleClose="callbackDrawer" size="80%">
-            <template #header="{ params }">
-                <h4 :id="params.titleId" :class="params.titleClass">库存明细</h4>
-            </template>
-            <TableBase border ref="TableDetailRef" :pagination="false" :columns="detailColumns"
-                :requestApi="Storehouse_Stock_Detail_List" :initParam="detailInitParam"
-                :dataCallback="detailDataCallback">
-                <template #table-header>
-                    <el-row class="head-search">
-                        <el-col :span="12"><el-form-item label="日期范围">
+		<Drawer ref="DrawerRef" :handleClose="callbackDrawer" size="80%">
+			<template #header="{ params }">
+				<h4 :id="params.titleId" :class="params.titleClass">库存明细</h4>
+			</template>
+			<TableBase border ref="TableDetailRef" :pagination="false" :columns="detailColumns"
+					   :requestApi="Storehouse_Stock_Detail_List" :initParam="detailInitParam"
+					   :dataCallback="detailDataCallback">
+				<template #table-header>
+					<el-row class="head-search">
+						<el-col :span="12">
+							<el-form-item label="日期范围">
 
-                                <el-date-picker v-model="T_date_detail" type="daterange" range-separator="~"
-                                    start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD"
-                                    value-format="YYYY-MM-DD" @change="dateDetailChange" /></el-form-item></el-col>
-                        <el-col :span="12">
-                            <el-button type="success" @click="confirmExpor(detailInitParam.T_product_id)">导出</el-button>
-                        </el-col>
-                    </el-row>
-                </template>
-                <template #right="{ row }">
-                    <InventoryStatisticsshowModel :rows="row" />
-                </template>
-            </TableBase>
-        </Drawer>
-    </div>
+								<el-date-picker v-model="T_date_detail" type="daterange" range-separator="~"
+												start-placeholder="开始时间" end-placeholder="结束时间"
+												format="YYYY-MM-DD"
+												value-format="YYYY-MM-DD" @change="dateDetailChange"/>
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-button type="success" @click="confirmExpor(detailInitParam.T_product_id)">导出
+							</el-button>
+						</el-col>
+					</el-row>
+				</template>
+				<template #right="{ row }">
+					<InventoryStatisticsshowModel :rows="row"/>
+				</template>
+			</TableBase>
+		</Drawer>
+	</div>
 </template>
 
 <style scoped lang="scss">
 @import '@/styles/var.scss';
 
 .export-popover {
-    padding: 5px;
-    display: flex;
-    justify-content: center;
+	padding: 5px;
+	display: flex;
+	justify-content: center;
 }
 
 :deep(.drawer__content) {
-    @include f-direction;
+	@include f-direction;
 }
 
 :deep(.el-drawer__header) {
-    margin-bottom: 0;
+	margin-bottom: 0;
 }
 
 .inventory-statistics {
-    height: 100%;
-    display: flex;
-    overflow: hidden;
+	height: 100%;
+	display: flex;
+	overflow: hidden;
 
-    .title {
-        width: 100%;
-        text-align: center;
-        line-height: 1.7em;
-        font-size: 20px;
-        color: #707b84;
-    }
+	.title {
+		width: 100%;
+		text-align: center;
+		line-height: 1.7em;
+		font-size: 20px;
+		color: #707b84;
+	}
 
-    :deep(.table-header),
-    :deep(.card) {
-        margin: 0;
-        border-radius: 8px;
-    }
+	:deep(.table-header),
+	:deep(.card) {
+		margin: 0;
+		border-radius: 8px;
+	}
 
-    .inventory-table {
-        @include f-direction;
-        z-index: 1;
-    }
+	.inventory-table {
+		@include f-direction;
+		z-index: 1;
+	}
 
-    .project-container {
-        @include f-direction;
-        z-index: 0;
-        margin-left: 12px;
-        width: calc(100% - 290px);
-    }
+	.project-container {
+		@include f-direction;
+		z-index: 0;
+		margin-left: 12px;
+		width: calc(100% - 290px);
+	}
 
-    .head-search {
-        width: 100%;
-        height: 33px;
-        overflow: hidden;
-        transition: all 0.5s ease-in-out;
+	.head-search {
+		width: 100%;
+		height: 33px;
+		overflow: hidden;
+		transition: all 0.5s ease-in-out;
 
-        .result-form.el-form .el-form-item {
-            margin-bottom: 0 !important;
-        }
+		.result-form.el-form .el-form-item {
+			margin-bottom: 0 !important;
+		}
 
-        .search-bottom {
-            margin-top: 18px;
-        }
-    }
+		.search-bottom {
+			margin-top: 18px;
+		}
+	}
 
-    .head-search.active {
-        height: 85px;
-    }
+	.head-search.active {
+		height: 85px;
+	}
 
-    .w-50 {
-        flex: 0 0 50%;
-    }
+	.w-50 {
+		flex: 0 0 50%;
+	}
 }
 </style>

+ 9 - 4
src/views/storehouse/inventory/InStorageEditSn.vue

@@ -35,7 +35,12 @@ const rulesSn = reactive<FormRules>({
   sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
 })
 
-const addSn = (formEl: FormInstance | undefined) => {
+const addSn = (e:any) => {
+	e.preventDefault()
+	addSns(ruleSnFormRef.value)
+}
+
+const addSns = (formEl: FormInstance | undefined) => {
   if (!formEl) return
   formEl.validate(async valid => {
     if (valid) {
@@ -152,16 +157,16 @@ defineExpose({
 </script>
 
 <template>
-  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
+  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%" :closeModal="false" >
     <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="sn">
-              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn(ruleSnFormRef)"   class="w-50" />
+              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn"   class="w-50" />
             </el-form-item>
           </el-form>
-          <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
+          <el-button type="primary" @click="addSns(ruleSnFormRef)">添加</el-button>
           <el-button type="success" @click="drawer = true">导入xlsx</el-button>
         </div>
       </template>

+ 10 - 4
src/views/storehouse/inventory/InStorageSn.vue

@@ -34,7 +34,13 @@ const rulesSn = reactive<FormRules>({
   sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
 })
 
-const addSn = (formEl: FormInstance | undefined) => {
+const addSn = (e:any) => {
+	e.preventDefault()
+	addSns(ruleSnFormRef.value)
+}
+
+const addSns = (formEl: FormInstance | undefined) => {
+	console.log("-------")
   if (!formEl) return
   formEl.validate(async valid => {
     if (valid) {
@@ -150,16 +156,16 @@ defineExpose({
 </script>
 
 <template>
-  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
+  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" :closeModal="false" 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="sn">
-              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn(ruleSnFormRef)"   class="w-50" />
+              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn"   class="w-50" />
             </el-form-item>
           </el-form>
-          <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
+          <el-button type="primary" @click="addSns(ruleSnFormRef)">添加</el-button>
           <el-button type="success" @click="drawer = true">导入xlsx</el-button>
         </div>
       </template>

+ 262 - 200
src/views/storehouse/outStock/OutStockDetail.vue

@@ -1,11 +1,13 @@
 <script setup lang="ts">
-import { ref, onMounted } from 'vue'
-import { GlobalStore } from '@/stores/index'
-import { useRoute, useRouter } from 'vue-router'
+import {onMounted, ref} from 'vue'
+import {GlobalStore} from '@/stores/index'
+import {useRoute, useRouter} from 'vue-router'
 import Drawer from '@/components/Drawer/index.vue'
-import { Storehouse_StockOut_Get,stockoutexcel } from '@/api/storehouse/index'
-import { InfoType } from '@/hooks/useDepot'
+import {stockoutexcel, Storehouse_StockOut_Get} from '@/api/storehouse/index'
+import {InfoType} from '@/hooks/useDepot'
 import ImageCom from '@/components/Image/index.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+
 
 const tableSnData = ref<any[]>([])
 const info = ref<InfoType | undefined>()
@@ -15,40 +17,40 @@ 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 ' }
+	{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 snColumns = [
-  { type: 'index', label: '序号', width: 80, align: 'center ' },
-  { label: 'SN', prop: 'sn', align: 'center ' }
+	{type: 'index', label: '序号', width: 80, align: 'center '},
+	{label: 'SN', prop: 'sn', align: 'center '}
 ]
 
-const stockInexcelFun = async (data:any)=>{
-    console.log(data,info.value);
-    const result:any = await stockoutexcel({T_number:info.value!.T_number})
-    if (result.Code === 200) {
-        window.open(result.Data)
-    }
+const stockInexcelFun = async (data: any) => {
+	console.log(data, info.value);
+	const result: any = await stockoutexcel({T_number: info.value!.T_number})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
 }
 
 
 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 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[]>([])
@@ -59,202 +61,262 @@ const tableData = ref<any[]>([])
 const callbackSnDrawer = (done: () => void) => done()
 
 const previewSn = (devicelist: string[]) => {
-  drawerSnRef.value?.openDrawer()
-  if (!devicelist) return
-  tableSnData.value = devicelist.map((item: string) => {
-    return {
-      sn: item
-    }
-  })
+	drawerSnRef.value?.openDrawer()
+	if (!devicelist) return
+	tableSnData.value = devicelist.map((item: string) => {
+		return {
+			sn: item
+		}
+	})
 }
 
 interface DeliveryType {
-  [propName: string]: string
+	[propName: string]: string
 }
 
 const delivery_type: DeliveryType = {
-  1: '自送',
-  2: '自提',
-  3: '快递'
+	1: '自送',
+	2: '自提',
+	3: '快递'
 }
 
 onMounted(() => {
-  getStorehouseContractGet()
+	getStorehouseContractGet()
 })
 </script>
 <template>
-  <div class="contract-detail">
-    <div class="info">
-        <div style="display: flex;justify-content: space-between">
-            <h1>出库详情</h1>
-            <el-button type="primary" icon="Download" @click="stockInexcelFun">导出excel</el-button>
-      </div>
-      
-      <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 :span="21">
-            <el-table
-              :data="tableData"
-              style="width: 100%"
-              border
-              stripe
-              :header-cell-style="{
+	<div class="contract-detail">
+		<div class="info">
+			<div style="display: flex;justify-content: space-between">
+				<h1>出库详情
+					<el-tag v-if="info?.T_state_str === '待审批'" type="warning" size="small" effect="dark"> 待审批
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '财务通过'" type="primary" size="small" effect="dark">
+						财务通过
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '财务驳回'" type="danger" size="small" effect="dark"> 财务驳回
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '总经理通过'" type="primary" size="small" effect="dark">
+						总经理通过
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '总经理驳回'" type="danger" size="small" effect="dark">
+						总经理驳回
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '已出库'" type="success" size="small" effect="dark"> 已出库
+					</el-tag>
+				</h1>
+				<el-button type="primary" icon="Download" @click="stockInexcelFun">导出excel</el-button>
+			</div>
+
+			<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_application_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'" show-overflow-tooltip>
-                  <template #default="{ row }" v-if="item.prop === item.name">
+						>
+							<template v-for="item in columns" :key="item.prop">
+								<el-table-column v-bind="item" v-if="item.fixed !== 'right'" show-overflow-tooltip>
+									<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>
-                    <ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img" />
-                    <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"
-                      @click="previewSn(row.T_device_list)"
-                      >查看</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_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 :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
-            ><span>{{ info?.T_receive_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_project! }}</span></el-col
-          >
-        </el-row>
-        <div v-if="info?.T_type === 2">
-          <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_delivery_type ? delivery_type[info.T_delivery_type] : '无' }}</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_signer_unit ? info.T_signer_unit : '无' }}</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_signer ? info.T_signer : '无' }}</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_signer_phone ? info.T_signer_phone : '无' }}</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_signer_date ? info.T_signer_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 :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
-              ><span>{{ info.T_courier_number ? info.T_courier_number : '无' }}</span></el-col
-            >
-          </el-row>
-        </div>
-        <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>
-    <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="30%">
-      <el-table
-        :data="tableSnData"
-        style="width: 100%; height: 99%"
-        :header-cell-style="{
+										<ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img"/>
+										<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"
+											@click="previewSn(row.T_device_list)"
+										>查看
+										</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_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 :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+					><span>{{ info?.T_company_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>{{
+								paymentMethodOptions.find((option: any) => option.id === info?.T_payment_method!)?.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_project! }}</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_receive_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_warehouse_name! }}</span></el-col
+					>
+				</el-row>
+				<div v-if="info?.T_type === 2">
+					<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_delivery_type ? delivery_type[info.T_delivery_type] : '无' }}</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_signer_unit ? info.T_signer_unit : '无' }}</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_signer ? info.T_signer : '无' }}</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_signer_phone ? info.T_signer_phone : '无' }}</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_signer_date ? info.T_signer_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 :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+						><span>{{ info.T_courier_number ? info.T_courier_number : '无' }}</span></el-col
+						>
+					</el-row>
+				</div>
+				<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>
+				<el-row v-if="info?.T_payment_method === 'A' || info?.T_payment_method === 'B'">
+					<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_finance_approval_opinion! }}</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_manager_approval_opinion! }}</span></el-col
+					>
+				</el-row>
+			</div>
+			<el-divider/>
+			<div class="submit">
+				<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 show-overflow-tooltip v-if="item.type === 'index'" v-bind="item" />
-          <el-table-column show-overflow-tooltip v-if="item.prop" v-bind="item" />
-        </template>
-      </el-table>
-    </Drawer>
-  </div>
+			>
+				<template v-for="item in snColumns" :key="item">
+					<el-table-column show-overflow-tooltip v-if="item.type === 'index'" v-bind="item"/>
+					<el-table-column show-overflow-tooltip v-if="item.prop" v-bind="item"/>
+				</template>
+			</el-table>
+		</Drawer>
+	</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;
-    }
-  }
+	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>

+ 5 - 0
src/views/storehouse/outStock/OutStockProduct.vue

@@ -135,6 +135,7 @@ const productColumns = [
   { prop: 'T_product_model', label: '产品型号', ellipsis: true },
   { prop: 'T_product_spec', label: '产品规格' },
   { prop: 'T_total', label: '库存数量' },
+  {prop: 'T_occupy', label: '占用库存', name: 'T_occupy'},
   { prop: 'T_product_relation_sn', label: '关联SN', name: 'T_product_relation_sn' }
 ]
 
@@ -221,6 +222,10 @@ defineExpose({
                 <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>
+				<span v-if="item.prop === 'T_occupy'">
+					<el-text v-if="row.T_occupy > 0" type="danger">{{row.T_occupy}}</el-text>
+					<el-text v-else type="info">{{row.T_occupy}}</el-text>
+				</span>
               <ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img" />
             </template>
           </el-table-column>

+ 1 - 1
src/views/storehouse/outStock/ReceiveOutStock.vue

@@ -59,7 +59,7 @@ const columns = [
   { 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_relation_sn' },
+  { label: '是否关联SN', prop: 'T_product_relation_sn', align: 'center ', width: 120, name: 'T_product_relation_sn' },
   { label: '库存数量', prop: 'T_total', align: 'center ' },
   { label: '*出库数量', prop: 'count', align: 'center ', name: 'count' },
   { label: '*关联设备', prop: 'sn', align: 'center ', name: 'sn' },

+ 2 - 0
src/views/storehouse/outStock/modules/InStorageEdit.vue

@@ -29,6 +29,8 @@ const form = reactive<InStoreageFormTypes>({
 	T_receive: '',
 	T_receive_name: '',
 	T_remark: '',
+	T_company_name: '',
+	T_payment_method: '',
 
 })
 

+ 10 - 4
src/views/storehouse/outStock/modules/InStorageEditSn.vue

@@ -35,7 +35,12 @@ const rulesSn = reactive<FormRules>({
   sn: [{ required: true, message: '请输入SN号', trigger: 'blur' }]
 })
 
-const addSn = (formEl: FormInstance | undefined) => {
+const addSn = (e:any) => {
+	e.preventDefault()
+	addSns(ruleSnFormRef.value)
+}
+
+const addSns = (formEl: FormInstance | undefined) => {
   if (!formEl) return
   formEl.validate(async valid => {
     if (valid) {
@@ -153,16 +158,17 @@ defineExpose({
 </script>
 
 <template>
-  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" size="50%">
+
+  <Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" :closeModal="false" 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="sn">
-              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn(ruleSnFormRef)"   class="w-50" />
+              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn"   class="w-50" />
             </el-form-item>
           </el-form>
-          <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>
+          <el-button type="primary" @click="addSns(ruleSnFormRef)">添加</el-button>
           <el-button type="success" @click="drawer = true">导入xlsx</el-button>
         </div>
       </template>

+ 250 - 0
src/views/storehouse/outStock/outStockApply/OutStockApply.vue

@@ -0,0 +1,250 @@
+<script setup lang="ts">
+import type {FormInstance} from 'element-plus'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import {useRouter} from 'vue-router'
+import {GlobalStore} from '@/stores'
+import {Delete, Edit, Van, View} from '@element-plus/icons-vue'
+import {nextTick, reactive, ref} from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type {ColumnProps} from '@/components/TableBase/interface'
+import {stockOutExcelBatch, Storehouse_StockOut_Apply_Del, Storehouse_StockOut_Apply_List,} from '@/api/storehouse'
+import {depotHooks} from '@/hooks/useDepot'
+import OutStorageEdit from './modules/OutStorageEdit.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+
+const router = useRouter()
+const formLabelWidth = ref('120px')
+const globalStore = GlobalStore()
+const ruleFormRef = ref<FormInstance>()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const multipleSelection = ref<any[]>([])
+
+const columns: ColumnProps[] = [
+	{type: 'selection', width: '44px', fixed: 'left'},
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_number', label: '出库单号'},
+	{prop: 'T_application_date', label: '申请日期'},
+	{prop: 'T_state_str', label: '状态', name: 'T_state_str'},
+	{prop: 'T_company_name', label: '公司名称'},
+	{prop: 'T_payment_method', label: '付款方式', name: 'T_payment_method', width: 150},
+	{prop: 'T_receive_name', label: '领取人'},
+	{prop: 'T_depot_name', label: '出库仓库'},
+	{prop: 'T_date', label: '出库日期'},
+	{prop: 'T_project', label: '关联项目'},
+	{prop: 'operation', label: '操作', width: 250, fixed: 'right', align: 'left '}
+]
+
+const form = reactive({
+	T_number: '',
+	T_remark: '',
+	T_delivery_type: '',
+	T_signer_unit: '',
+	T_signer: '',
+	T_signer_phone: '',
+	T_signer_date: '',
+	T_courier_number: ''
+})
+
+// 搜索
+const stateOptions = reactive([
+	{name: '待审批', id: 1},
+	{name: '财务通过', id: 2},
+	{name: '财务驳回', id: 3},
+	{name: '总经理通过', id: 4},
+	{name: '总经理驳回', id: 5},
+	{name: '已出库', id: 6},
+])
+
+/**
+ * 查看详情
+ */
+const preview = (number: string) => {
+	router.push({name: 'OutStockDetail', params: {number}})
+}
+const OutStorageRef = ref()
+/**
+ * 编辑
+ */
+const previewEdit = (row: any) => {
+	OutStorageRef.value?.openDrawer()
+	OutStorageRef.value?.getStorehouseContractGet(row.T_number)
+	for (let key in OutStorageRef.value?.form) {
+		if (row.hasOwnProperty(key)) OutStorageRef.value.form[key] = row[key];
+	}
+
+}
+// 搜索
+const T_date = ref<string[]>([])
+const initParam = reactive({
+	User_tokey: globalStore.GET_User_tokey,
+	T_end_date: '',
+	T_start_date: '',
+	T_depot_id: '',
+	T_name: '',
+	T_state:''
+})
+const searchHandle = () => {
+	initParam.T_end_date = T_date.value ? T_date.value[1] : ''
+	initParam.T_start_date = T_date.value ? T_date.value[0] : ''
+	TableRef.value?.searchTable()
+}
+
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	formEl.resetFields()
+}
+
+/**
+ * 删除
+ */
+const deleteFun = (row: any) => {
+	ElMessageBox.confirm(
+		'删除操作,是否立即删除?',
+		'删除',
+		{
+			confirmButtonText: '立即删除',
+			cancelButtonText: '取消',
+			type: 'warning',
+			center: true,
+		}
+	).then(async () => {
+		const result: any = await Storehouse_StockOut_Apply_Del({T_number: row})
+		if (result.Code == 200) {
+			ElMessage.success('删除成功')
+			TableRef.value?.searchTable()
+		}
+	}).catch(() => {
+	})
+}
+
+// 拿到仓库列表
+const {options} = depotHooks()
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+	return row.T_number
+}
+const stockOutExcelFun = async () => {
+	if (multipleSelection.value.length === 0) {
+		ElMessage.warning('请选择出库单!!!')
+		return
+	}
+	let T_number_list = ''
+	for (let item of multipleSelection.value) {
+		T_number_list += item.T_number + '|'
+	}
+
+	const result: any = await stockOutExcelBatch({T_number_list: T_number_list})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
+	nextTick(() => {
+		multipleSelection.value = []
+		TableRef.value?.clearSelection()
+	})
+}
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val
+	console.log(multipleSelection.value)
+}
+</script>
+
+<template>
+	<div class="out-stock">
+		<TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_StockOut_Apply_List" :initParam="initParam"
+				   :getRowKey="getRowKey"
+				   :selection-change="handleSelectionChange"
+		>
+			<template #table-header>
+				<div class="input-suffix">
+					<el-row :gutter="20" style="margin-bottom: 0">
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">出库编号:</span>
+							<el-input
+								v-model="initParam.T_name"
+								class="w-50 m-2"
+								type="text"
+								placeholder="出库编号搜索"
+								clearable
+								@change="searchHandle"
+							/>
+						</el-col>
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">状态:</span>
+							<el-select v-model="initParam.T_state" class="w-50 m-2" clearable placeholder="请选择状态~">
+								<el-option v-for="item in stateOptions" :key="item.id" :label="item.name"
+										   :value="item.id"/>
+							</el-select>
+							<el-button type="primary" @click="searchHandle">搜索</el-button>
+						</el-col>
+						<el-col :xl="14" :lg="14" :md="14" class="btn"
+						>
+							<el-button type="primary" @click="router.push('/receiveOutStockApply')">出库申请</el-button>
+							<el-button type="success" icon="Download" @click="stockOutExcelFun">导出excel</el-button>
+
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+			<template #T_payment_method="{ row }">
+				<el-text type="info">{{
+						paymentMethodOptions.find((option: any) => option.id === row.T_payment_method)?.name || ''
+					}}
+				</el-text>
+
+			</template>
+			<template #T_state_str="{ row }">
+				<el-text v-if="row.T_state_str === '待审批'" type="warning"> 待审批</el-text>
+				<el-text v-if="row.T_state_str === '财务通过'" type="primary"> 财务通过</el-text>
+				<el-text v-if="row.T_state_str === '财务驳回'" type="danger"> 财务驳回</el-text>
+				<el-text v-if="row.T_state_str === '总经理通过'" type="primary"> 总经理通过</el-text>
+				<el-text v-if="row.T_state_str === '总经理驳回'" type="danger"> 总经理驳回</el-text>
+				<el-text v-if="row.T_state_str === '已出库'" type="success"> 已出库</el-text>
+			</template>
+			<template #right="{ row }">
+				<el-button link type="success" size="small" :icon="View" @click="preview(row.T_number)">详情</el-button>
+				<el-button link type="primary" size="small" :icon="Edit" @click="previewEdit(row)"
+						   :disabled="[2,4,6].includes(row.T_state)"
+				>编辑
+				</el-button>
+				<el-button link type="danger" size="small" :icon="Delete" @click="deleteFun(row.T_number)"
+						   :disabled="[2,4,6].includes(row.T_state)"
+				>删除
+				</el-button>
+			</template>
+		</TableBase>
+		<OutStorageEdit ref="OutStorageRef" :options="options" @onUpdateList="searchHandle"/>
+	</div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.scss';
+
+.out-stock {
+	@include f-direction;
+
+	:deep(.el-drawer__header) {
+		margin-bottom: 0;
+	}
+
+	.input-suffix {
+		width: 100%;
+
+		.inline-flex {
+			white-space: nowrap;
+		}
+	}
+
+	.btn {
+		display: flex;
+		justify-content: right;
+
+		.el-button {
+			padding: 0 20px;
+		}
+	}
+}
+</style>

+ 189 - 0
src/views/storehouse/outStock/outStockApply/OutStockApplyFinance.vue

@@ -0,0 +1,189 @@
+<script setup lang="ts">
+import {ElMessage} from 'element-plus'
+import {useRouter} from 'vue-router'
+import {GlobalStore} from '@/stores'
+import {Van, View,Check} from '@element-plus/icons-vue'
+import {nextTick, reactive, ref} from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type {ColumnProps} from '@/components/TableBase/interface'
+import {stockOutExcelBatch, Storehouse_StockOut_Finance_List,} from '@/api/storehouse'
+import {depotHooks} from '@/hooks/useDepot'
+import OutStorageEdit from './modules/OutStorageEdit.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+import {fnMd5} from "@/utils/common";
+
+const router = useRouter()
+const globalStore = GlobalStore()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const multipleSelection = ref<any[]>([])
+
+const columns: ColumnProps[] = [
+	{type: 'selection', width: '44px', fixed: 'left'},
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_number', label: '出库单号'},
+	{prop: 'T_application_date', label: '申请日期'},
+	{prop: 'T_state_str', label: '状态', name: 'T_state_str'},
+	{prop: 'T_company_name', label: '公司名称'},
+	{prop: 'T_payment_method', label: '付款方式', name: 'T_payment_method', width: 150},
+	{prop: 'T_receive_name', label: '领取人'},
+	{prop: 'T_depot_name', label: '出库仓库'},
+	{prop: 'T_date', label: '出库日期'},
+	{prop: 'T_project', label: '关联项目'},
+	{prop: 'operation', label: '操作', width: 250, fixed: 'right', align: 'left '}
+]
+
+// 搜索
+const stateOptions = reactive([
+	{name: '待审批', id: 1},
+	{name: '财务通过', id: 2},
+	{name: '财务驳回', id: 3},
+])
+
+
+/**
+ * 查看详情
+ */
+const preview = (number: string) => {
+	router.push({name: 'OutStockDetail', params: {number}})
+}
+const OutStockAudit = (number: string, type: string) => {
+	router.push({name: 'OutStockAudit', params: {number, type}})
+}
+
+const OutStorageRef = ref()
+
+// 搜索
+const T_date = ref<string[]>([])
+const initParam = reactive({
+	User_tokey: globalStore.GET_User_tokey,
+	T_end_date: '',
+	T_start_date: '',
+	T_depot_id: '',
+	T_name: '',
+	T_state:''
+})
+const searchHandle = () => {
+	initParam.T_end_date = T_date.value ? T_date.value[1] : ''
+	initParam.T_start_date = T_date.value ? T_date.value[0] : ''
+	TableRef.value?.searchTable()
+}
+
+// 拿到仓库列表
+const {options} = depotHooks()
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+	return row.T_number
+}
+const stockOutExcelFun = async () => {
+	if (multipleSelection.value.length === 0) {
+		ElMessage.warning('请选择出库单!!!')
+		return
+	}
+	let T_number_list = ''
+	for (let item of multipleSelection.value) {
+		T_number_list += item.T_number + '|'
+	}
+
+	const result: any = await stockOutExcelBatch({T_number_list: T_number_list})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
+	nextTick(() => {
+		multipleSelection.value = []
+		TableRef.value?.clearSelection()
+	})
+}
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val
+	console.log(multipleSelection.value)
+}
+</script>
+
+<template>
+	<div class="out-stock">
+		<TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_StockOut_Finance_List"
+				   :initParam="initParam"
+				   :getRowKey="getRowKey"
+				   :selection-change="handleSelectionChange"
+		>
+			<template #table-header>
+				<div class="input-suffix">
+					<el-row :gutter="20" style="margin-bottom: 0">
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">出库编号:</span>
+							<el-input
+								v-model="initParam.T_name"
+								class="w-50 m-2"
+								type="text"
+								placeholder="出库编号搜索"
+								clearable
+								@change="searchHandle"
+							/>
+						</el-col>
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">状态:</span>
+							<el-select v-model="initParam.T_state" class="w-50 m-2" clearable placeholder="请选择状态~">
+								<el-option v-for="item in stateOptions" :key="item.id" :label="item.name"
+										   :value="item.id"/>
+							</el-select>
+							<el-button type="primary" @click="searchHandle">搜索</el-button>
+						</el-col>
+						<el-col :xl="14" :lg="14" :md="14" class="btn">
+							<el-button type="success" icon="Download" @click="stockOutExcelFun">导出excel</el-button>
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+			<template #T_payment_method="{ row }">
+				<el-text type="info">{{
+						paymentMethodOptions.find((option: any) => option.id === row.T_payment_method)?.name || ''
+					}}
+				</el-text>
+
+			</template>
+			<template #T_state_str="{ row }">
+				<el-text v-if="row.T_state_str === '待审批'" type="warning"> 待审批</el-text>
+				<el-text v-if="row.T_state_str === '财务通过'" type="success"> 财务通过</el-text>
+				<el-text v-if="row.T_state_str === '财务驳回'" type="danger"> 财务驳回</el-text>
+			</template>
+			<template #right="{ row }">
+				<el-button link type="success" size="small" :icon="View" @click="preview(row.T_number)">详情</el-button>
+				<el-button link type="warning" size="small" :icon="Check" @click="OutStockAudit(row.T_number,'Finance')"
+						   :disabled="[2].includes(row.T_state)"
+				>审批
+				</el-button>
+			</template>
+		</TableBase>
+		<OutStorageEdit ref="OutStorageRef" :options="options" @onUpdateList="searchHandle"/>
+	</div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.scss';
+
+.out-stock {
+	@include f-direction;
+
+	:deep(.el-drawer__header) {
+		margin-bottom: 0;
+	}
+
+	.input-suffix {
+		width: 100%;
+
+		.inline-flex {
+			white-space: nowrap;
+		}
+	}
+
+	.btn {
+		display: flex;
+		justify-content: right;
+
+		.el-button {
+			padding: 0 20px;
+		}
+	}
+}
+</style>

+ 189 - 0
src/views/storehouse/outStock/outStockApply/OutStockApplyManager.vue

@@ -0,0 +1,189 @@
+<script setup lang="ts">
+import {ElMessage} from 'element-plus'
+import {useRouter} from 'vue-router'
+import {GlobalStore} from '@/stores'
+import {Van, View,Check} from '@element-plus/icons-vue'
+import {nextTick, reactive, ref} from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type {ColumnProps} from '@/components/TableBase/interface'
+import {stockOutExcelBatch, Storehouse_StockOut_Manager_List,} from '@/api/storehouse'
+import {depotHooks} from '@/hooks/useDepot'
+import OutStorageEdit from './modules/OutStorageEdit.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+
+const router = useRouter()
+const globalStore = GlobalStore()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const multipleSelection = ref<any[]>([])
+
+const columns: ColumnProps[] = [
+	{type: 'selection', width: '44px', fixed: 'left'},
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_number', label: '出库单号'},
+	{prop: 'T_application_date', label: '申请日期'},
+	{prop: 'T_state_str', label: '状态', name: 'T_state_str'},
+	{prop: 'T_company_name', label: '公司名称'},
+	{prop: 'T_payment_method', label: '付款方式', name: 'T_payment_method', width: 150},
+	{prop: 'T_receive_name', label: '领取人'},
+	{prop: 'T_depot_name', label: '出库仓库'},
+	{prop: 'T_date', label: '出库日期'},
+	{prop: 'T_project', label: '关联项目'},
+	{prop: 'operation', label: '操作', width: 250, fixed: 'right', align: 'left '}
+]
+
+// 搜索
+const stateOptions = reactive([
+	{name: '待审批', id: 1},
+	{name: '财务通过', id: 2},
+	{name: '总经理通过', id: 4},
+	{name: '总经理驳回', id: 5},
+])
+
+/**
+ * 查看详情
+ */
+const preview = (number: string) => {
+	router.push({name: 'OutStockDetail', params: {number}})
+}
+const OutStockAudit = (number: string, type: string) => {
+	router.push({name: 'OutStockAudit', params: {number, type}})
+}
+
+const OutStorageRef = ref()
+
+// 搜索
+const T_date = ref<string[]>([])
+const initParam = reactive({
+	User_tokey: globalStore.GET_User_tokey,
+	T_end_date: '',
+	T_start_date: '',
+	T_depot_id: '',
+	T_name: '',
+	T_state:''
+})
+const searchHandle = () => {
+	initParam.T_end_date = T_date.value ? T_date.value[1] : ''
+	initParam.T_start_date = T_date.value ? T_date.value[0] : ''
+	TableRef.value?.searchTable()
+}
+
+// 拿到仓库列表
+const {options} = depotHooks()
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+	return row.T_number
+}
+const stockOutExcelFun = async () => {
+	if (multipleSelection.value.length === 0) {
+		ElMessage.warning('请选择出库单!!!')
+		return
+	}
+	let T_number_list = ''
+	for (let item of multipleSelection.value) {
+		T_number_list += item.T_number + '|'
+	}
+
+	const result: any = await stockOutExcelBatch({T_number_list: T_number_list})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
+	nextTick(() => {
+		multipleSelection.value = []
+		TableRef.value?.clearSelection()
+	})
+}
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val
+	console.log(multipleSelection.value)
+}
+</script>
+
+<template>
+	<div class="out-stock">
+		<TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_StockOut_Manager_List"
+				   :initParam="initParam"
+				   :getRowKey="getRowKey"
+				   :selection-change="handleSelectionChange"
+		>
+			<template #table-header>
+				<div class="input-suffix">
+					<el-row :gutter="20" style="margin-bottom: 0">
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">出库编号:</span>
+							<el-input
+								v-model="initParam.T_name"
+								class="w-50 m-2"
+								type="text"
+								placeholder="出库编号搜索"
+								clearable
+								@change="searchHandle"
+							/>
+						</el-col>
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">状态:</span>
+							<el-select v-model="initParam.T_state" class="w-50 m-2" clearable placeholder="请选择状态~">
+								<el-option v-for="item in stateOptions" :key="item.id" :label="item.name"
+										   :value="item.id"/>
+							</el-select>
+							<el-button type="primary" @click="searchHandle">搜索</el-button>
+						</el-col>
+						<el-col :xl="14" :lg="14" :md="14" class="btn">
+							<el-button type="success" icon="Download" @click="stockOutExcelFun">导出excel</el-button>
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+			<template #T_payment_method="{ row }">
+				<el-text type="info">{{
+						paymentMethodOptions.find((option: any) => option.id === row.T_payment_method)?.name || ''
+					}}
+				</el-text>
+
+			</template>
+			<template #T_state_str="{ row }">
+				<el-text v-if="row.T_state_str === '待审批'" type="warning">待审批</el-text>
+				<el-text v-if="row.T_state_str === '财务通过'" type="primary">财务通过</el-text>
+				<el-text v-if="row.T_state_str === '总经理通过'" type="success">总经理通过</el-text>
+				<el-text v-if="row.T_state_str === '总经理驳回'" type="danger">总经理驳回</el-text>
+			</template>
+			<template #right="{ row }">
+				<el-button link type="success" size="small" :icon="View" @click="preview(row.T_number)">详情</el-button>
+				<el-button link type="warning" size="small" :icon="Check" @click="OutStockAudit(row.T_number,'Manager')"
+						   :disabled="[4].includes(row.T_state)"
+				>审批
+				</el-button>
+			</template>
+		</TableBase>
+		<OutStorageEdit ref="OutStorageRef" :options="options" @onUpdateList="searchHandle"/>
+	</div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.scss';
+
+.out-stock {
+	@include f-direction;
+
+	:deep(.el-drawer__header) {
+		margin-bottom: 0;
+	}
+
+	.input-suffix {
+		width: 100%;
+
+		.inline-flex {
+			white-space: nowrap;
+		}
+	}
+
+	.btn {
+		display: flex;
+		justify-content: right;
+
+		.el-button {
+			padding: 0 20px;
+		}
+	}
+}
+</style>

+ 233 - 0
src/views/storehouse/outStock/outStockApply/OutStockApplyWarehouse.vue

@@ -0,0 +1,233 @@
+<script setup lang="ts">
+import type {FormInstance} from 'element-plus'
+import {ElMessage, ElMessageBox} from 'element-plus'
+import {useRouter} from 'vue-router'
+import {GlobalStore} from '@/stores'
+import {dayJs} from '@/utils/common'
+import {Edit, View} from '@element-plus/icons-vue'
+import {nextTick, reactive, ref} from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type {ColumnProps} from '@/components/TableBase/interface'
+import {stockOutExcelBatch, Storehouse_StockOut_Apply_Del, Storehouse_StockOut_Warehouse_List,} from '@/api/storehouse'
+import {depotHooks} from '@/hooks/useDepot'
+import OutStorageWarehouse from './modules/OutStorageWarehouse.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+
+const router = useRouter()
+const globalStore = GlobalStore()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const multipleSelection = ref<any[]>([])
+const columns: ColumnProps[] = [
+	{type: 'selection', width: '44px', fixed: 'left'},
+	{type: 'index', label: '序号', width: 80},
+	{prop: 'T_number', label: '出库单号'},
+	{prop: 'T_application_date', label: '申请日期'},
+	{prop: 'T_state_str', label: '状态', name: 'T_state_str'},
+	{prop: 'T_company_name', label: '公司名称'},
+	{prop: 'T_payment_method', label: '付款方式', name: 'T_payment_method', width: 150},
+	{prop: 'T_receive_name', label: '领取人'},
+	{prop: 'T_depot_name', label: '出库仓库'},
+	{prop: 'T_date', label: '出库日期'},
+	{prop: 'T_project', label: '关联项目'},
+	{prop: 'operation', label: '操作', width: 250, fixed: 'right', align: 'left '}
+]
+
+// 搜索
+const stateOptions = reactive([
+	{name: '待出库', id: 4},
+	{name: '已出库', id: 6},
+])
+
+/**
+ * 查看详情
+ */
+const preview = (number: string) => {
+	router.push({name: 'OutStockDetail', params: {number}})
+}
+const OutStorageRef = ref()
+const getFormattedDate = (date: string | null | undefined) => {
+	return date || dayJs().format('YYYY-MM-DD')
+}
+/**
+ * 编辑
+ */
+const previewEdit = (row: any) => {
+	OutStorageRef.value?.openDrawer()
+	OutStorageRef.value?.getStorehouseContractGet(row.T_number)
+	for (let key in OutStorageRef.value?.form) {
+		// if (row.hasOwnProperty(key)) OutStorageRef.value.form[key] = row[key];
+		if (row.hasOwnProperty(key)) {
+			OutStorageRef.value.form[key] = key === 'T_date'
+				? getFormattedDate(row[key])
+				: row[key]
+		}
+	}
+
+}
+// 搜索
+const T_date = ref<string[]>([])
+const initParam = reactive({
+	User_tokey: globalStore.GET_User_tokey,
+	T_end_date: '',
+	T_start_date: '',
+	T_depot_id: '',
+	T_name: '',
+	T_state: ''
+})
+const searchHandle = () => {
+	initParam.T_end_date = T_date.value ? T_date.value[1] : ''
+	initParam.T_start_date = T_date.value ? T_date.value[0] : ''
+	TableRef.value?.searchTable()
+}
+
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	formEl.resetFields()
+}
+
+/**
+ * 删除
+ */
+const deleteFun = (row: any) => {
+	ElMessageBox.confirm(
+		'删除操作,是否立即删除?',
+		'删除',
+		{
+			confirmButtonText: '立即删除',
+			cancelButtonText: '取消',
+			type: 'warning',
+			center: true,
+		}
+	).then(async () => {
+		const result: any = await Storehouse_StockOut_Apply_Del({T_number: row})
+		if (result.Code == 200) {
+			ElMessage.success('删除成功')
+			TableRef.value?.searchTable()
+		}
+	}).catch(() => {
+	})
+}
+
+// 拿到仓库列表
+const {options} = depotHooks()
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+	return row.T_number
+}
+const stockOutExcelFun = async () => {
+	if (multipleSelection.value.length === 0) {
+		ElMessage.warning('请选择出库单!!!')
+		return
+	}
+	let T_number_list = ''
+	for (let item of multipleSelection.value) {
+		T_number_list += item.T_number + '|'
+	}
+
+	const result: any = await stockOutExcelBatch({T_number_list: T_number_list})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
+	nextTick(() => {
+		multipleSelection.value = []
+		TableRef.value?.clearSelection()
+	})
+}
+const handleSelectionChange = (val: any[]) => {
+	multipleSelection.value = val
+	console.log(multipleSelection.value)
+}
+</script>
+
+<template>
+	<div class="out-stock">
+		<TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_StockOut_Warehouse_List"
+				   :initParam="initParam"
+				   :getRowKey="getRowKey"
+				   :selection-change="handleSelectionChange"
+		>
+			<template #table-header>
+				<div class="input-suffix">
+					<el-row :gutter="20" style="margin-bottom: 0">
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">出库编号:</span>
+							<el-input
+								v-model="initParam.T_name"
+								class="w-50 m-2"
+								type="text"
+								placeholder="出库编号搜索"
+								clearable
+								@change="searchHandle"
+							/>
+						</el-col>
+
+						<el-col :xl="5" :lg="5" :md="5" style="display: flex">
+							<span class="inline-flex items-center">状态:</span>
+							<el-select v-model="initParam.T_state" class="w-50 m-2" clearable placeholder="请选择状态~">
+								<el-option v-for="item in stateOptions" :key="item.id" :label="item.name"
+										   :value="item.id"/>
+							</el-select>
+							<el-button type="primary" @click="searchHandle">搜索</el-button>
+						</el-col>
+						<el-col :xl="14" :lg="14" :md="14" class="btn">
+							<el-button type="success" icon="Download" @click="stockOutExcelFun">导出excel</el-button>
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+			<template #T_payment_method="{ row }">
+				<el-text type="info">{{
+						paymentMethodOptions.find((option: any) => option.id === row.T_payment_method)?.name || ''
+					}}
+				</el-text>
+
+			</template>
+			<template #T_state_str="{ row }">
+				<el-text v-if="row.T_state_str === '总经理通过'" type="warning"> 待出库</el-text>
+				<el-text v-if="row.T_state_str === '已出库'" type="success"> 已出库</el-text>
+			</template>
+			<template #right="{ row }">
+				<el-button link type="success" size="small" :icon="View" @click="preview(row.T_number)">详情</el-button>
+				<el-button link type="primary" size="small" :icon="Edit" @click="previewEdit(row)"
+						   :disabled="[6].includes(row.T_state)"
+				>出库
+				</el-button>
+
+			</template>
+		</TableBase>
+		<OutStorageWarehouse ref="OutStorageRef" :options="options" @onUpdateList="searchHandle"/>
+	</div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.scss';
+
+.out-stock {
+	@include f-direction;
+
+	:deep(.el-drawer__header) {
+		margin-bottom: 0;
+	}
+
+	.input-suffix {
+		width: 100%;
+
+		.inline-flex {
+			white-space: nowrap;
+		}
+	}
+
+	.btn {
+		display: flex;
+		justify-content: right;
+
+		.el-button {
+			padding: 0 20px;
+		}
+	}
+}
+</style>

+ 293 - 0
src/views/storehouse/outStock/outStockApply/OutStockAudit.vue

@@ -0,0 +1,293 @@
+<script setup lang="ts">
+import {nextTick, onMounted, reactive, ref} from 'vue'
+import {GlobalStore} from '@/stores/index'
+import {useRoute, useRouter} from 'vue-router'
+import {stockoutexcel, Storehouse_StockOut_Audit, Storehouse_StockOut_Get} from '@/api/storehouse/index'
+import {InfoType, OutStockAuditFormType} from '@/hooks/useDepot'
+import ImageCom from '@/components/Image/index.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+import {ElMessage, type FormInstance} from "element-plus";
+
+const ruleFormRef = ref<FormInstance>()
+const info = ref<InfoType | undefined>()
+const globalStore = GlobalStore()
+const route = useRoute()
+const router = useRouter()
+const dialogVisible = ref(false)
+const auditType = ref('')
+
+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 initParam = reactive<OutStockAuditFormType>({
+	T_number: '',
+	T_audit: 0,
+	T_approval_opinion: '',
+	T_type: '',
+})
+
+const stockOutExcelFun = async (data: any) => {
+	console.log(data, info.value);
+	const result: any = await stockoutexcel({T_number: info.value!.T_number})
+	if (result.Code === 200) {
+		window.open(result.Data)
+	}
+}
+
+
+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[]>([])
+
+
+const openDrawer = (audit: string) => {
+	dialogVisible.value = true
+	auditType.value = audit
+}
+
+// 2财务通过 3财务驳回 4总经理通过 5总经理驳回
+const StockOutAudit = async () => {
+	const type = route.params.type as string
+	console.log("type---------", type, auditType.value)
+
+	if (type === 'Finance') {
+		// 财务审核分支
+		if (auditType.value === '通过') {
+			initParam.T_audit = 2 // 财务通过
+		} else if (auditType.value === '驳回') {
+			initParam.T_audit = 3 // 财务不通过
+		}
+	} else {
+		// 总经理审核分支
+		if (auditType.value === '通过') {
+			initParam.T_audit = 4 // 总经理通过
+		} else if (auditType.value === '驳回') {
+			initParam.T_audit = 5 // 总经理不通过
+		}
+	}
+
+
+	initParam.T_number = route.params.number as string
+	initParam.T_type = type
+	const result: any = await Storehouse_StockOut_Audit({
+		User_tokey: globalStore.GET_User_tokey,
+		...initParam,
+	})
+	console.log('财务提交', result)
+	if (result.Code === 200) {
+		ElMessage.success('提交成功!')
+		nextTick(() => {
+			if (ruleFormRef.value) {
+				ruleFormRef.value.resetFields()
+			}
+			dialogVisible.value = false
+			router.back()
+		})
+	}
+}
+
+
+onMounted(() => {
+	getStorehouseContractGet()
+})
+</script>
+<template>
+	<div class="contract-detail">
+		<div class="info">
+			<div style="display: flex;justify-content: space-between">
+				<h1>出库详情
+					<el-tag v-if="info?.T_state_str === '待审批'" type="warning" size="small" effect="dark"> 待审批
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '财务通过'" type="primary" size="small" effect="dark">
+						财务通过
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '财务驳回'" type="danger" size="small" effect="dark"> 财务驳回
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '总经理通过'" type="primary" size="small" effect="dark">
+						总经理通过
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '总经理驳回'" type="danger" size="small" effect="dark">
+						总经理驳回
+					</el-tag>
+					<el-tag v-if="info?.T_state_str === '已出库'" type="success" size="small" effect="dark"> 已出库
+					</el-tag>
+				</h1>
+				<el-button type="primary" icon="Download" @click="stockOutExcelFun">导出excel</el-button>
+			</div>
+
+			<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_application_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'" show-overflow-tooltip>
+									<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>
+										<ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img"/>
+										<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>
+							</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_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 :xs="11" :sm="9" :md="7" :lg="6" :xl="5"
+					><span>{{ info?.T_receive_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_company_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>{{
+								paymentMethodOptions.find((option: any) => option.id === info?.T_payment_method!)?.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_project! }}</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_remark! }}</span></el-col
+					>
+				</el-row>
+				<el-row v-if="info?.T_payment_method === 'A' || info?.T_payment_method === 'B'">
+					<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_finance_approval_opinion! }}</span></el-col
+					>
+				</el-row>
+
+			</div>
+
+			<el-divider/>
+
+			<div class="submit">
+				<el-button type="danger" round @click="openDrawer('驳回')">驳回</el-button>
+				<el-button type="success" round @click="openDrawer('通过')">通过</el-button>
+			</div>
+		</div>
+		<el-dialog title="审批意见" v-model="dialogVisible" width="30%" draggable>
+			<el-form :model="initParam" ref="approvalFormRef">
+				<el-form-item label="审批意见" prop="T_approval_opinion">
+					<el-input v-model="initParam.T_approval_opinion" :rows="3" type="textarea"
+							  placeholder="请输入审批意见"></el-input>
+				</el-form-item>
+			</el-form>
+			<div class="submit">
+			<el-button @click="dialogVisible = false">取消</el-button>
+			<el-button type="primary" @click="StockOutAudit">提交</el-button>
+			</div>
+		</el-dialog>
+	</div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.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;
+		}
+	}
+	.submit {
+		display: flex;
+		justify-content: right;
+	}
+}
+</style>

+ 279 - 0
src/views/storehouse/outStock/outStockApply/OutStockProduct.vue

@@ -0,0 +1,279 @@
+<script setup lang="ts">
+import {
+  Storehouse_Stock_List,
+  Storehouse_ProductClass_List,
+  Storehouse_Product_Model_List,
+  Storehouse_Product_Name_List
+} from '@/api/storehouse/index'
+import { ElMessage } from 'element-plus'
+import { GlobalStore } from '@/stores/index'
+import Drawer from '@/components/Drawer/index.vue'
+import { ref, reactive, onMounted, nextTick, watch } from 'vue'
+import { default as vElTableInfiniteScroll } from 'el-table-infinite-scroll'
+import ImageCom from '@/components/Image/index.vue'
+
+let total = 0
+const loading = ref(false)
+const autoSelect = ref('')
+const selectTable = ref()
+const globalStore = GlobalStore()
+const classOptions = ref<any[]>([])
+const modelOptions = ref<any[]>([])
+const NameOptions = ref<any[]>([])
+const tableProductData = ref<any[]>([])
+const drawerProductRef = ref<InstanceType<typeof Drawer> | null>(null)
+
+const initParam = reactive({
+  User_tokey: globalStore.GET_User_tokey,
+  T_product_name: '',
+  T_product_model: '',
+  T_product_class: '',
+  page: 1,
+  page_z: 20
+})
+const callbackProductDrawer = (done: () => void) => done()
+const querySearchAsync = async (queryString: string) => {
+  if (queryString) {
+    loading.value = true
+    globalStore.SET_isloading(true)
+    const results = await getNameAsync(queryString)
+    NameOptions.value = results
+    globalStore.SET_isloading(false)
+    loading.value = false
+  }
+}
+
+const getProductModelList = async () => {
+  globalStore.SET_isloading(true)
+  const res: any = await Storehouse_Product_Model_List({ T_name: autoSelect.value })
+  modelOptions.value = res.Data.map((item: any, index: number) => {
+    return {
+      value: item,
+      index: index
+    }
+  })
+  globalStore.SET_isloading(false)
+}
+const handleSelect = (item: any) => {
+  initParam.T_product_name = item
+  getProductModelList()
+}
+// 搜索模型
+const searchModelHandle = () => {
+  total = 0
+  initParam.page = 1
+  clearProdctData()
+  getProductList(props.depotId)
+}
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+  return row.Id
+}
+
+// 加载第二个抽屉数据
+const load = () => {
+  if (initParam.page && total === tableProductData.value.length) {
+    ElMessage.warning('没有更多数据了!!')
+    return
+  }
+  initParam.page++
+  getProductList(props.depotId)
+}
+// 勾选产品
+const ProductselectionChange = (selection: any[], row: any) => emit('ontableData', row)
+const ProductSelectionAllChange = (selection: any[]) => emit('ontableDataAll', selection)
+
+const getNameAsync = async (str: string): Promise<any> => {
+  const res: any = await Storehouse_Product_Name_List({ T_name: str, T_class: initParam.T_product_class })
+  if (!res.Data) return
+  return res.Data.map((item: any, index: number) => {
+    return {
+      value: item,
+      index: index
+    }
+  })
+}
+
+/**
+ * 获取产品列表
+ */
+const getProductList = async (depotId: number) => {
+  const res: any = await Storehouse_Stock_List({ ...initParam, T_name: autoSelect.value, T_depot_id: depotId })
+  res.Data.Data ? tableProductData.value.push(...res.Data.Data) : clearProdctData()
+  total = res.Data.Num
+}
+
+// 获取产品分类
+const getProductClassList = async () => {
+  const res: any = await Storehouse_ProductClass_List({ page: 1, page_z: 999 })
+  classOptions.value = res.Data.Data
+}
+const props = withDefaults(defineProps<{ depotId: number }>(), {
+  depotId: 0
+})
+
+watch(
+  () => props.depotId,
+  cur => {
+    getProductList(cur)
+  }
+)
+
+onMounted(() => {
+  // getProductList()
+  !classOptions.value.length && getProductClassList()
+})
+
+const productColumns = [
+  { type: 'selection', width: 80 },
+  { prop: 'T_product_img', label: '产品图片', name: 'T_product_img' },
+  { prop: 'T_product_name', label: '产品名称' },
+  { prop: 'T_product_model', label: '产品型号' },
+  { prop: 'T_product_class_name', label: '产品分类' },
+  { prop: 'T_product_model', label: '产品型号', ellipsis: true },
+  { prop: 'T_product_spec', label: '产品规格' },
+  { prop: 'T_total', label: '库存数量' },
+  { prop: 'T_occupy', label: '占用库存', name: 'T_occupy'},
+  { prop: 'T_product_relation_sn', label: '关联SN', name: 'T_product_relation_sn' }
+]
+
+const clearProdctData = () => (tableProductData.value = [])
+const openDrawer = () => drawerProductRef.value?.openDrawer()
+const clearSelection = () => selectTable.value?.clearSelection()
+const selectTableChange = (row: any) => {
+  nextTick(() => {
+    selectTable.value?.toggleRowSelection(row, false)
+  })
+}
+const emit = defineEmits<{ (event: 'ontableData', value: any): void; (event: 'ontableDataAll', value: any[]): void }>()
+
+defineExpose({
+  openDrawer,
+  clearSelection,
+  clearProdctData,
+  selectTableChange
+})
+</script>
+
+<template>
+  <Drawer ref="drawerProductRef" :handleClose="callbackProductDrawer" size="70%">
+    <template #header="{ params }">
+      <h4 :id="params.titleId" :class="params.titleClass">选择产品</h4>
+    </template>
+    <el-card class="box-card" shadow="never">
+      <template #header>
+        <div class="input-suffix">
+          <el-row :gutter="20" style="margin-bottom: 0">
+            <el-col :xl="5" :lg="8" :md="10" class="d-flex">
+              <span class="inline-flex items-center">产品分类:</span>
+              <el-select v-model="initParam.T_product_class" clearable placeholder="请选择分类~">
+                <el-option v-for="item in classOptions" :key="item.Id" :label="item.T_name" :value="item.Id" />
+              </el-select>
+            </el-col>
+            <el-col :xl="7" :lg="8" :md="10" class="d-flex">
+              <span class="inline-flex items-center">产品名称:</span>
+              <el-select
+                v-model="autoSelect"
+                filterable
+                clearable
+                remote
+                reserve-keyword
+                placeholder="按产品名称搜索"
+                remote-show-suffix
+                :remote-method="querySearchAsync"
+                :loading="loading"
+                @change="handleSelect"
+              >
+                <el-option v-for="item in NameOptions" :key="item.value" :label="item.value" :value="item.value" />
+              </el-select>
+            </el-col>
+            <el-col :xl="7" :lg="8" :md="12" class="d-flex">
+              <span class="inline-flex items-center">产品型号:</span>
+              <el-select v-model="initParam.T_product_model" clearable placeholder="请选择型号~">
+                <el-option v-for="item in modelOptions" :key="item.index" :label="item.value" :value="item.value" />
+              </el-select>
+              <el-button type="primary" @click="searchModelHandle">搜索</el-button>
+            </el-col>
+          </el-row>
+        </div>
+      </template>
+      <el-table
+        ref="selectTable"
+        :row-key="getRowKey"
+        :data="tableProductData"
+        style="width: 100%; height: 99%"
+        :header-cell-style="{
+          background: '#dedfe0',
+          height: '50px'
+        }"
+        v-el-table-infinite-scroll="load"
+        :infinite-scroll-immediate="false"
+        infinite-scroll-distance="'50px'"
+        @select="ProductselectionChange"
+        @select-all="ProductSelectionAllChange"
+      >
+        <template v-for="item in productColumns" :key="item">
+          <el-table-column v-if="item.type === 'index' || item.type === 'selection'" align="center" v-bind="item" />
+          <el-table-column show-overflow-tooltip v-if="!item.ellipsis && item.prop" v-bind="item" align="center">
+            <template #default="{ row }">
+              <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>
+				<span v-if="item.prop === 'T_occupy'">
+					<el-text v-if="row.T_occupy > 0" type="danger">{{row.T_occupy}}</el-text>
+					<el-text v-else type="info">{{row.T_occupy}}</el-text>
+				</span>
+              <ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img" />
+            </template>
+          </el-table-column>
+          <el-table-column show-overflow-tooltip v-if="item.ellipsis && item.prop === 'T_model'" align="center" 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 show-overflow-tooltip v-if="item.ellipsis && item.prop === 'T_remark'" align="center" v-bind="item">
+            <template #default="{ row }">
+              <el-tooltip effect="customized" placement="left">
+                <template #content>
+                  <div class="tooltip-content">{{ row.T_remark }}</div>
+                </template>
+                {{ row.T_remark }}
+              </el-tooltip>
+            </template>
+          </el-table-column>
+        </template>
+      </el-table>
+    </el-card>
+  </Drawer>
+</template>
+
+<style scoped lang="scss">
+.tooltip-content {
+  max-width: 500px;
+  overflow-y: auto;
+}
+
+.box-card {
+  height: 100%;
+  :deep(.el-card__body) {
+    height: calc(100% - 70px);
+  }
+  .sn-header {
+    display: flex;
+    justify-content: end;
+  }
+  .input-suffix {
+    width: 100%;
+    .inline-flex {
+      white-space: nowrap;
+    }
+    .d-flex {
+      display: flex;
+    }
+  }
+}
+</style>

+ 277 - 0
src/views/storehouse/outStock/outStockApply/ReceiveOutStockApply.vue

@@ -0,0 +1,277 @@
+<script setup lang="ts">
+import type {FormInstance, FormRules} from 'element-plus'
+import {ElMessage} from 'element-plus'
+import {nextTick, reactive, ref} from 'vue'
+import {useRouter} from 'vue-router'
+import {GlobalStore} from '@/stores/index'
+import {Delete} from '@element-plus/icons-vue'
+import {Storehouse_StockOut_Apply} from '@/api/storehouse/index'
+import InStorageSn from '@/views/storehouse/inventory/InStorageSn.vue'
+import OutStockProduct from './OutStockProduct.vue'
+import {depotHooks, ReceiveApplyFormType} from '@/hooks/useDepot'
+import ImageCom from '@/components/Image/index.vue'
+import {paymentMethodOptions} from '@/hooks/useTablePublic'
+
+
+const router = useRouter()
+const tableData = ref<any[]>([])
+const globalStore = GlobalStore()
+const formLabelWidth = ref('120px')
+const ruleFormRef = ref<FormInstance>()
+const drawerSnRef = ref<InstanceType<typeof InStorageSn> | null>(null)
+const drawerProductRef = ref<InstanceType<typeof OutStockProduct> | null>(null)
+
+const form = reactive<ReceiveApplyFormType>({
+	T_project: '',
+	T_number: '',
+	T_depot_id: undefined,
+	T_product: '',
+	T_remark: '',
+	T_contract_number: '',
+	T_company_name: '',
+	T_payment_method: ''
+})
+
+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: [{required: true, validator: validate_T_product, trigger: 'blur'}],
+	T_depot_id: [{required: true, message: '请选择仓库', trigger: 'blur'}],
+	T_company_name: [{required: true, message: '请输入公司名称', trigger: 'blur'}],
+	T_payment_method: [{required: true, message: '请选择付款方式', trigger: 'blur'}],
+})
+
+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_model', 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_total', align: 'center '},
+	{label: '*出库数量', prop: 'count', align: 'center ', name: 'count'},
+	{prop: 'operation', label: '操作', width: 80, fixed: 'right'}
+]
+
+
+const countBlurHandle = () => {
+	form.T_product = tableData.value.map(item => {
+		if (!item.count ) return undefined
+		if (item.count > item.T_total) return undefined
+		return `${item.T_product_id},${item.count}|`
+	})
+}
+const getDeviceSnToProduct = () => {
+	const isEmpty = determineSNorCount()
+	if (isEmpty && isEmpty === 'count') return [undefined]
+
+	return tableData.value.map((item: any) => {
+		let product: any = ''
+		product = `${item.T_product_id}-${item.count}-`
+		return product + '|'
+	})
+}
+/**
+ * 判断sn or 数量是否为空
+ */
+const determineSNorCount = () => {
+	for (const item of tableData.value) {
+		if ((!item.count) || item.count > item.T_total) return 'count'
+	}
+	return false
+}
+
+const OutStorageApply = (formEl: FormInstance | undefined) => {
+
+	if (!formEl) return
+	form.T_product = getDeviceSnToProduct()
+	formEl.validate(async valid => {
+		if (valid) {
+			const res: any = await Storehouse_StockOut_Apply({
+				User_tokey: globalStore.GET_User_tokey,
+				...form,
+				T_product: form.T_product.join(''),
+			})
+			if (res.Code === 200) {
+				ElMessage.success('出库申请提交成功!')
+				nextTick(() => {
+					resetForm(ruleFormRef.value)
+					router.back()
+				})
+			}
+		}
+	})
+}
+
+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 closeReceive = () => {
+	resetForm(ruleFormRef.value)
+	router.back()
+}
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	tableData.value = []
+	drawerSnRef.value?.clearDeviceSn()
+	drawerProductRef.value?.clearSelection()
+	formEl.resetFields()
+}
+/**
+ * 添加产品
+ */
+const AddProductionDetailed = () => drawerProductRef.value?.openDrawer()
+/**
+ * 产品选择 是否
+ */
+const ProductselectionChange = (row: any) => {
+	const index = tableData.value.findIndex((item: any) => item.Id === row.Id)
+	if (index === -1) {
+		row.count = ''
+		tableData.value.push(row)
+	} else {
+		tableData.value.splice(index, 1)
+	}
+}
+/**
+ * 全选
+ */
+const ProductSelectionAllChange = (selection: any[]) => {
+	tableData.value = selection
+}
+
+// 拿到仓库列表
+const {options} = depotHooks()
+const changeDepot = () => drawerProductRef.value?.clearProdctData()
+</script>
+
+<template>
+	<div class="receive-outStock">
+		<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_depot_id">
+				<el-select v-model="form.T_depot_id" class="w-50" clearable placeholder="请选择出库仓库~"
+						   @change="changeDepot">
+					<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_company_name">
+				<el-input v-model="form.T_company_name" placeholder="请输入公司名称" class="w-50"/>
+			</el-form-item>
+			<el-form-item label="付款方式:" class="m-b-6" :label-width="formLabelWidth" prop="T_payment_method">
+				<el-select v-model="form.T_payment_method" class="w-50 m-2" clearable placeholder="请选择付款方式~">
+					<el-option v-for="item in paymentMethodOptions" :key="item.id" :label="item.name" :value="item.id"/>
+				</el-select>
+			</el-form-item>
+			<el-form-item label="关联项目:" :label-width="formLabelWidth">
+				<el-input v-model="form.T_project" placeholder="请输入关联项目" class="w-50"/>
+			</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 show-overflow-tooltip v-bind="item"
+										 v-if="item.fixed !== 'right' && !item.ellipsis">
+							<template #header v-if="item.prop === 'count'">
+								<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-model.number="row.count"
+									type="text"
+									autocomplete="off"
+									@blur="countBlurHandle"
+								/>
+								<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>
+								<ImageCom v-if="item.prop === 'T_product_img'" :src="row.T_product_img"/>
+							</template>
+						</el-table-column>
+						<el-table-column show-overflow-tooltip 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>
+					<template #append>
+						<el-button type="primary" @click="AddProductionDetailed">
+							<el-icon>
+								<Plus/>
+							</el-icon>
+							<span style="margin-left: 6px">添加产品</span>
+						</el-button>
+					</template>
+				</el-table>
+			</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="closeReceive">取消</el-button>
+					<el-button color="#626aef" @click="OutStorageApply(ruleFormRef)">提交</el-button>
+				</el-divider>
+			</div>
+		</el-form>
+		<OutStockProduct
+			ref="drawerProductRef"
+			:depotId="form.T_depot_id"
+			@ontableData="ProductselectionChange"
+			@ontableDataAll="ProductSelectionAllChange"
+		/>
+	</div>
+</template>
+<style scoped lang="scss">
+@import '../index.scss';
+</style>

+ 366 - 0
src/views/storehouse/outStock/outStockApply/modules/OutStorageEdit.vue

@@ -0,0 +1,366 @@
+<script setup lang="ts">
+import type {FormInstance, FormRules} from 'element-plus'
+import {ElMessage} from 'element-plus'
+import OutStorageEditSn from './OutStorageEditSn.vue'
+import {nextTick, reactive, ref} from 'vue'
+import {GlobalStore} from '@/stores'
+import Drawer from '@/components/Drawer/index.vue'
+import {InStoreageFormTypes, ReceiveApplyFormType} from '@/hooks/useDepot'
+import OutStorageProduct from './OutStorageProduct.vue'
+import {Delete} from '@element-plus/icons-vue'
+import {Storehouse_StockOut_Apply_Edit, Storehouse_StockOut_EditGet, Storehouse_StockOut_Get} from '@/api/storehouse'
+import ImageCom from '@/components/Image/index.vue'
+import ReceiveUser from '@/views/storehouse/outStock/receiveUser.vue'
+import {paymentMethodOptions} from "@/hooks/useTablePublic";
+
+const tableData = ref<any[]>([])
+const globalStore = GlobalStore()
+const formLabelWidth = ref('120px')
+const ruleFormRef = ref<FormInstance>()
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+const drawerSnEditRef = ref<InstanceType<typeof OutStorageEditSn> | null>(null)
+const drawerProductRef = ref<InstanceType<typeof OutStorageProduct> | null>(null)
+
+const form = reactive<ReceiveApplyFormType>({
+	T_number: '',
+	T_depot_id: '',
+	T_product: '',//明细拼接
+	T_project: '',//关联项目
+	T_remark: '',
+	T_contract_number: '',
+	T_company_name: '',
+	T_payment_method: ''
+})
+
+const validate_T_product = (rule: any, value: any, callback: any) => {
+	// console.log('验证',value)
+	if (value == 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_depot_id: [{required: true, message: '请选择仓库', trigger: 'blur'}],
+	T_company_name: [{required: true, message: '请输入公司名称', trigger: 'blur'}],
+	T_payment_method: [{required: true, message: '请选择付款方式', trigger: 'blur'}],
+})
+
+const columns = [
+	{type: 'index', label: '序号', width: 80, align: 'center '},
+	{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_number', 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'},
+	{prop: 'operation', label: '操作', width: 80, fixed: 'right'}
+]
+
+const countBlurHandle = () => {
+	form.T_product = tableData.value.map(item => {
+		if (!item.count && item.T_relation_sn !== 1) return undefined
+		return `${item.T_product_id},${item.count}|`
+	})
+}
+const getDeviceSnToProduct = () => {
+	const isEmpty = determineSNorCount()
+	if (isEmpty && isEmpty === 'count') return [undefined]
+	if (isEmpty && isEmpty === 'sn') return [null]
+	let arr = [...tableData.value]
+	let mapArr: any = []
+	let flag = false
+	for (const item of arr) {
+		if (item.count == 0) {
+			flag = true
+			break;
+		}
+		mapArr.push(item.T_product_id + '-' + item.count + '-' + (item.T_device_list ? item.T_device_list.join(',') : ''))
+	}
+	return flag ? undefined : mapArr.join('|') + '|'
+}
+/**
+ * 判断sn or 数量是否为空
+ */
+const determineSNorCount = () => {
+	for (const item of tableData.value) {
+		if (item.count < 1 && item.T_relation_sn !== 1) return 'count'  //数量必大于0
+		// if (item.T_relation_sn === 1 && !DeviceSnData.get(item.Id) && !DeviceSnData.size) return 'sn'
+	}
+	return false
+}
+
+const ApplyEditStorage = (formEl: FormInstance | undefined) => {
+
+	if (!formEl) return
+	form.T_product = getDeviceSnToProduct()
+	formEl.validate(async valid => {
+		if (valid) {
+			const res: any = await Storehouse_StockOut_Apply_Edit({
+				...form
+			})
+			if (res.Code === 200) {
+				ElMessage.success('编辑成功!')
+				drawerProductRef.value?.clearSelection()
+				nextTick(() => {
+					emit('onUpdateList')
+					resetForm(ruleFormRef.value)
+					drawerRef.value?.closeDrawer()
+				})
+			}
+		}
+	})
+}
+
+const deleteProduct = (row: any) => {
+	tableData.value = tableData.value.filter(item => item.Id !== row.Id)
+
+	// 设置产品的选中
+	drawerProductRef.value?.selectTableChange(row)
+	// 删除设备得sn
+	drawerSnEditRef.value?.deleteDeviceSn(row.Id)
+}
+
+const callbackDrawer = (done: () => void) => {
+	resetForm(ruleFormRef.value)
+	done()
+}
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	drawerProductRef.value?.clearSelection()
+	drawerSnEditRef.value?.clearDeviceSn()
+	tableData.value = []
+	formEl.resetFields()
+}
+
+/**
+ * 添加产品
+ */
+const AddProductionDetailed = () => {
+	drawerProductRef.value?.openDrawer()
+	drawerProductRef.value?.getProductList()
+	// drawerProductRef.value?.getStockTotalList(form.T_depot_id)
+}
+/**
+ * 单选
+ */
+const ProductselectionChange = (row: any) => {
+	row.T_product_id = row.Id
+	const index = tableData.value.findIndex((item: any) => item.T_product_id === row.T_product_id)
+	if (index === -1) {
+		row.count = 0
+		tableData.value.push(row)
+	} else {
+		tableData.value.splice(index, 1)
+	}
+}
+/**
+ * 全选
+ */
+const ProductSelectionAllChange = (selection: any[]) => {
+	console.log('全选', selection)
+	let arr = [...selection]
+	arr.forEach((item: any) => {
+		item.T_product_id = item.Id
+	})
+	tableData.value = selection
+}
+
+
+const getStorehouseContractGet = async (Id: any) => {
+	const res: any = await Storehouse_StockOut_Get({User_tokey: globalStore.GET_User_tokey, T_number: Id})
+	if (res.Code === 200) {
+		let arr = res.Data.T_Product
+		arr.forEach((item: any) => {
+			tableData.value.push({
+				Id: item.Id,
+				T_class_name: item.T_product_class_name,
+				T_img: item.T_product_img,
+				T_model: item.T_number,
+				T_name: item.T_product_name,
+				count: item.T_num,
+				T_relation_sn: item.T_product_relation_sn,
+				T_spec: item.T_product_spec,
+				T_device_list: item.T_device_list,
+				T_product_id: item.T_product_id
+			})
+		})
+	}
+}
+
+/**
+ * 添加sn 号
+ */
+
+const addDeviceSn = (obj: any) => {
+	drawerSnEditRef.value?.addDeviceSn(obj.Id, 1, obj.T_product_id)
+	drawerSnEditRef.value!.drawerSnRef?.openDrawer()
+	if (obj.T_device_list) drawerSnEditRef.value!.tableSnData = [...obj.T_device_list].map(item => ({sn: item}));
+}
+/**
+ * 自动计算 count
+ */
+const autoGetCount = (length: number, id: number, arr: any) => {
+	tableData.value.forEach((item: any) => {
+		if (item.Id === id) {
+			item.T_device_list = arr
+			item.count = length
+		}
+	})
+}
+/**
+ * 关闭 取消
+ */
+const closeInStorage = () => {
+	resetForm(ruleFormRef.value)
+	drawerRef.value?.closeDrawer()
+}
+// 注册事件
+const emit = defineEmits<{ (event: 'onUpdateList'): void }>()
+
+// 接受props
+interface ItemType {
+	T_name: string
+	Id: number
+}
+
+interface PropsType {
+	options?: ItemType[]
+}
+
+const props = defineProps<PropsType>()
+/**
+ * 出库调用
+ */
+const openDrawer = () => drawerRef.value?.openDrawer()
+
+
+
+defineExpose({
+	openDrawer, getStorehouseContractGet, form
+})
+</script>
+<template>
+	<div class="inStorage-form">
+		<Drawer ref="drawerRef" :handleClose="callbackDrawer" size="80%">
+			<template #header="{ params }">
+				<h4 :id="params.titleId" :class="params.titleClass">编辑</h4>
+			</template>
+			<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" 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" :disabled="true" clearable
+							   placeholder="请选择出库仓库~">
+						<el-option v-for="item in props.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_company_name">
+					<el-input v-model="form.T_company_name" placeholder="请输入公司名称" class="w-50"/>
+				</el-form-item>
+				<el-form-item label="付款方式:" class="m-b-6" :label-width="formLabelWidth" prop="T_payment_method">
+					<el-select v-model="form.T_payment_method" class="w-50 m-2" clearable placeholder="请选择付款方式~">
+						<el-option v-for="item in paymentMethodOptions" :key="item.id" :label="item.name" :value="item.id"/>
+					</el-select>
+				</el-form-item>
+				<el-form-item label="关联项目:" :label-width="formLabelWidth" prop="T_project">
+					<el-input v-model="form.T_project" type="text" placeholder="关联项目" class="w-50"/>
+				</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 show-overflow-tooltip v-bind="item"
+											 v-if="item.fixed !== 'right' && !item.ellipsis">
+								<template #header v-if="item.prop === 'count'">
+									<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-model.number="row.count"
+										type="text"
+										autocomplete="off"
+										@blur="countBlurHandle"
+									/>
+									<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>
+                  					</span>
+									<ImageCom v-if="item.prop == 'T_img'" :src="row.T_img"/>
+								</template>
+							</el-table-column>
+							<el-table-column show-overflow-tooltip 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>
+						<template #append>
+							<el-button type="primary" @click="AddProductionDetailed">
+								<el-icon>
+									<Plus/>
+								</el-icon>
+								<span style="margin-left: 6px">添加产品</span>
+							</el-button>
+						</template>
+					</el-table>
+				</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="closeInStorage">取消</el-button>
+						<el-button color="#626aef" @click="ApplyEditStorage(ruleFormRef)">提交</el-button>
+					</el-divider>
+				</div>
+
+			</el-form>
+		</Drawer>
+		<OutStorageProduct
+			ref="drawerProductRef"
+			:depotId="form.T_depot_id"
+			:selectProductData="tableData"
+			@ontableData="ProductselectionChange"
+			@ontableDataAll="ProductSelectionAllChange"
+		/>
+
+	</div>
+</template>
+<style scoped lang="scss">
+</style>

+ 238 - 0
src/views/storehouse/outStock/outStockApply/modules/OutStorageEditSn.vue

@@ -0,0 +1,238 @@
+<script setup lang="ts">
+import {nextTick, reactive, ref} from 'vue'
+import * as XLSX from 'xlsx';
+import {Delete} from '@element-plus/icons-vue'
+import Drawer from '@/components/Drawer/index.vue'
+import type {FormInstance, FormRules} from 'element-plus'
+import {ElMessage} from 'element-plus'
+import {Storehouse_Device_Check} from '@/api/storehouse'
+
+type Fn = () => void
+
+interface FormSnType {
+	Id?: number
+	sn: string
+	type?: number
+	T_product_id?: number
+}
+
+const snTable = ref()
+const snCount = ref(null)
+const SNDataMap = new Map<number, FormSnType[]>()
+const tableSnData = ref<FormSnType[]>([])
+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,
+	sn: '',
+	type: undefined,
+	T_product_id: undefined
+})
+const rulesSn = reactive<FormRules>({
+	sn: [{required: true, message: '请输入SN号', trigger: 'blur'}]
+})
+
+const addSn = (e:any) => {
+	e.preventDefault()
+	addSns(ruleSnFormRef.value)
+}
+
+const addSns = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	formEl.validate(async valid => {
+		if (valid) {
+			if (snCount.value !== null && snCount.value <= tableSnData.value.length) {
+				ElMessage.error('出库数量与扫码数量不一致')
+				return
+			}
+			if (formSn.sn.length === 16 || formSn.sn.length === 24) {
+				if (formSn.sn.length == 24) {
+					formSn.sn = formSn.sn.substring(2, formSn.sn.length - 6)
+				}
+				const res: any = await Storehouse_Device_Check({
+					T_product_id: formSn.T_product_id,
+					T_sn: formSn.sn,
+					T_type: formSn.type
+				})
+				if (res.Code === 200) {
+					tableSnData.value.unshift({sn: formSn.sn})
+					tableSnData.value = tableSnData.value.filter((value, index, self) => {  //去重
+						return self.findIndex(t => (t.sn === value.sn)) === index;
+					});
+					nextTick(() => {
+						resetSnForm(ruleSnFormRef.value)
+					})
+				}
+			} else {
+				ElMessage.error('扫描设备异常')
+				nextTick(() => {
+					resetSnForm(ruleSnFormRef.value)
+				})
+				return
+			}
+		}
+	})
+}
+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)
+	let arrs = tableSnData.value.map((item: any) => item.sn);
+	emit('onCount', SNDataMap.get(formSn.Id as number)?.length, formSn.Id as number, arrs)
+	done()
+	nextTick(() => {
+		resetSnForm(ruleSnFormRef.value)
+		tableSnData.value = []
+	})
+}
+
+const emit = defineEmits<{ (event: 'onCount', value: any, id: number, mapArr: any): void }>()
+
+const resetSnForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	formEl.resetFields()
+}
+
+const addDeviceSn = (id: number, type: number, T_product_id: number) => {
+	console.log('1212', id, type)
+	formSn.Id = id
+	formSn.type = type
+	formSn.T_product_id = T_product_id
+	if (SNDataMap.has(id)) {
+		tableSnData.value = SNDataMap.get(id) as FormSnType[]
+	} else {
+		SNDataMap.set(id, [])
+	}
+	drawerSnRef.value?.openDrawer()
+}
+
+const drawer = ref(false)
+/**
+ * 导入xlsx
+ */
+
+// 组件状态变化的回调
+const uploadExcelFile = (event: any) => {
+	const files = event.target.files;
+	if (files.length === 0) return;
+	const file = files[0];
+	const reader = new FileReader();
+	reader.onload = (e: any) => {
+		const data = new Uint8Array(e.target.result);
+		const workbook = XLSX.read(data, {type: 'array'});
+		// 假设我们知道第一个工作表包含我们需要的数据
+		const firstSheetName = workbook.SheetNames[0];
+		const worksheet: any = workbook.Sheets[firstSheetName];
+		// 假设我们知道 t_sn 是第一列
+		const tSnColumn = 'A'; // 或者使用 XLSX.utils.decode_col(columnNumber) 来从列号获取列名
+		const columnNumber = XLSX.utils.decode_col(tSnColumn); // 但实际上我们可能直接知道列号,如 0
+		// 使用 sheet_to_json 但只选择我们需要的列
+		const json = XLSX.utils.sheet_to_json(worksheet, {
+			header: 1,
+			range: XLSX.utils.decode_range(worksheet['!ref'])
+		});
+		// 如果表头不是第一行,或者你不想要表头,可以调整 header 选项
+		// 提取 t_sn 列的数据(假设表头在第一行,且 t_sn 是第一列)
+		let tSnData: any = json.map((row: any) => row[0]); // 假设 t_sn 是第一列,所以使用 row[0]
+		let snArray = tSnData.map((sn: any) => ({sn: sn}));
+		snArray = snArray.slice(1)
+		let arrs = [...tableSnData.value, ...snArray]
+		// 去重
+		let seen = new Set();
+		tableSnData.value = arrs.filter((item: any) => {
+			return seen.has(item.sn) ? false : seen.add(item.sn) || true;
+		});
+
+		console.log('打印', tableSnData.value)
+		// 注意:如果 t_sn 列不是第一列,你需要调整索引号
+		// 例如,如果 t_sn 是第三列,则使用 row[2]
+	};
+
+	reader.readAsArrayBuffer(file);
+
+};
+const getDeviceSn = () => SNDataMap
+const clearDeviceSn = () => SNDataMap.clear()
+const deleteDeviceSn = (id: number) => SNDataMap.delete(id)
+defineExpose({
+	getDeviceSn,
+	addDeviceSn,
+	clearDeviceSn,
+	deleteDeviceSn, tableSnData, drawerSnRef, snCount
+})
+</script>
+
+<template>
+	<Drawer ref="drawerSnRef" :handleClose="callbackSnDrawer" :snCount="snCount"  :closeModal="false" 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="sn">
+							<el-input v-model="formSn.sn" type="text" placeholder="请输入SN"
+									  @keyup.enter="addSn" class="w-50"/>
+						</el-form-item>
+					</el-form>
+					<el-button type="primary" @click="addSns(ruleSnFormRef)">添加</el-button>
+					<el-button type="success" @click="drawer = true">导入xlsx</el-button>
+				</div>
+			</template>
+			<div>数量:{{ tableSnData.length }}</div>
+			<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 show-overflow-tooltip 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>
+		<el-drawer v-model="drawer" title="导入xlsx" size="50%" :destroy-on-close="true">
+			<input type="file" @change="uploadExcelFile" accept=".xlsx, .xls"/>
+		</el-drawer>
+	</Drawer>
+
+</template>
+
+<style scoped lang="scss">
+.box-card {
+	height: 100%;
+
+	:deep(.el-card__body) {
+		height: calc(100% - 70px);
+	}
+
+	.sn-header {
+		display: flex;
+		justify-content: end;
+	}
+}
+</style>

+ 356 - 0
src/views/storehouse/outStock/outStockApply/modules/OutStorageProduct.vue

@@ -0,0 +1,356 @@
+<script setup lang="ts">
+import {
+	Storehouse_Product_List,
+	Storehouse_Product_Model_List,
+	Storehouse_Product_Name_List,
+	Storehouse_ProductClass_List,
+	Storehouse_Stock_List
+} from '@/api/storehouse'
+import {ElMessage} from 'element-plus'
+import {GlobalStore} from '@/stores'
+import Drawer from '@/components/Drawer/index.vue'
+import {computed, nextTick, onMounted, reactive, ref} from 'vue'
+import {default as vElTableInfiniteScroll} from 'el-table-infinite-scroll'
+import ImageCom from '@/components/Image/index.vue'
+import {ReceiveFormType} from "@/hooks/useDepot";
+
+let total = 0
+const autoSelect = ref('')
+const selectTable = ref()
+const loading = ref(false)
+const globalStore = GlobalStore()
+const NameOptions = ref<any[]>([])
+const classOptions = ref<any[]>([])
+const modelOptions = ref<any[]>([])
+const tableProductData = ref<any[]>([])
+const productList = ref<any[]>([])
+const tableStockData:any = ref([])
+const drawerProductRef = ref<InstanceType<typeof Drawer> | null>(null)
+const tableData = ref<any[]>([])
+
+// props
+const props = defineProps<{ selectProductData?: any[], depotId: any }>()
+const selectProductData = ref(props.selectProductData)
+const emit = defineEmits<{ (event: 'ontableData', value: any): void; (event: 'ontableDataAll', value: any[]): void }>()
+
+const form = reactive<ReceiveFormType>({
+	T_type: 1,
+	T_uuid: '',
+	T_receive: '',
+	T_project: '',
+	T_number: '',
+	T_depot_id: undefined,
+	T_product: '',
+	T_date: '',
+	T_remark: '',
+	T_contract_number: ''
+})
+
+const initParam = reactive({
+	User_tokey: globalStore.GET_User_tokey,
+	T_name: '',
+	T_model: '',
+	T_class: '',
+	page: 1,
+	page_z: 20
+})
+const callbackProductDrawer = (done: () => void) => done()
+const querySearchAsync = async (queryString: string) => {
+	if (queryString) {
+		loading.value = true
+		globalStore.SET_isloading(true)
+		const results = await getNameAsync(queryString)
+		NameOptions.value = results
+		globalStore.SET_isloading(false)
+		loading.value = false
+	}
+}
+
+const getProductModelList = async () => {
+	globalStore.SET_isloading(true)
+	const res: any = await Storehouse_Product_Model_List({T_name: autoSelect.value})
+	modelOptions.value = res.Data.map((item: any, index: number) => {
+		return {
+			value: item,
+			index: index
+		}
+	})
+	globalStore.SET_isloading(false)
+}
+const handleSelect = (item: any) => {
+	initParam.T_name = item
+	getProductModelList()
+}
+// 搜索模型
+const searchModelHandle = () => {
+	total = 0
+	initParam.page = 1
+	tableProductData.value = []
+	getProductList()
+}
+
+// 保存选中的数据id,row-key就是要指定一个key标识这一行的数据
+const getRowKey = (row: any) => {
+  return row.Id
+}
+
+// 加载第二个抽屉数据
+const load = () => {
+	// if (initParam.page && total === tableProductData.value.length) {
+	// 	ElMessage.warning('没有更多数据了!!')
+	// 	return
+	// }
+	// initParam.page++
+	// getProductList()
+}
+// 勾选产品
+const ProductselectionChange = (selection: any[], row: any) => emit('ontableData', row)
+const ProductSelectionAllChange = (selection: any[]) => emit('ontableDataAll', selection)
+
+const getNameAsync = async (str: string): Promise<any> => {
+	const res: any = await Storehouse_Product_Name_List({T_name: str, T_class: initParam.T_class})
+	if (!res.Data) return
+	return res.Data.map((item: any, index: number) => {
+		return {
+			value: item,
+			index: index
+		}
+	})
+}
+
+/**
+ * 获取产品列表
+ */
+const getStockTotalList =  async(depotId: number) => {
+
+	 return new Promise( (reslove:any)=>{
+		 Storehouse_Stock_List({...initParam, page_z: 9999, T_depot_id: depotId}).then((res:any)=>{
+			 reslove(res.Data.Data)
+		 })
+	})
+
+}
+
+// 获取产品的列表
+const getProductList = async () => {
+	const res: any = await Storehouse_Product_List({...initParam, page_z: 9999, T_name: autoSelect.value})
+	tableProductData.value=[...res.Data.Data || []]
+	tableStockData.value = await getStockTotalList(props.depotId)
+
+	// 创建 Map 存储 arr2 中对象,键为 Id
+	const idMap = new Map(tableProductData.value.map(item => [item.Id, item]));
+	// 生成合并后的新数组
+	productList.value = tableStockData.value
+		.filter((item: any) => idMap.has(item.T_product_id))  // 筛选存在对应关系的数据
+		.map((item: any) => ({
+			...item,
+			...idMap.get(item.T_product_id)  // 合并两个数据源
+		}));
+
+	// tableProductData.value.push(...arr2)
+
+	total = res.Data.Num
+	if (selectProductData.value?.length) {
+		// 设置产品的选中
+		productList.value.forEach((row: any) => {
+			setTimeout(() => {
+				const matchedIndex = selectProductData.value?.findIndex((item: any) => item.T_product_id == row.Id)
+				selectTable.value?.toggleRowSelection(row, matchedIndex != -1)
+			});
+		})
+	}
+}
+
+// 获取产品分类
+const getProductClassList = async () => {
+	const res: any = await Storehouse_ProductClass_List({page: 1, page_z: 999})
+	classOptions.value = res.Data.Data
+}
+
+onMounted(() => {
+	// getProductList()
+	!classOptions.value.length && getProductClassList()
+})
+
+const productColumns = [
+	{type: 'selection', width: 80},
+	{prop: 'T_img', label: '产品图片', name: 'T_img'},
+	{prop: 'T_name', label: '产品名称'},
+	{prop: 'T_class_name', label: '产品分类'},
+	{prop: 'T_model', label: '产品型号', ellipsis: true},
+	{prop: 'T_spec', label: '产品规格'},
+	{prop: 'T_relation_sn', label: '关联SN', name: 'T_relation_sn'},
+	{prop: 'T_total', label: '库存数量'},
+	{prop: 'T_occupy', label: '占用库存', name: 'T_occupy'},
+	{prop: 'T_remark', label: '备注', ellipsis: true}
+]
+const countBlurHandle = () => {
+	form.T_product = tableData.value.map(item => {
+		if (!item.count && item.T_product_relation_sn !== 1) return undefined
+		if (item.count > item.T_total) return undefined
+		return `${item.T_product_id},${item.count}|`
+	})
+}
+
+const openDrawer = () => drawerProductRef.value?.openDrawer()
+const clearSelection = () => {
+	initParam.page = 1
+	tableProductData.value = []
+	selectTable.value?.clearSelection()
+}
+const selectTableChange = (row: any) => {
+	nextTick(() => {
+		selectTable.value?.toggleRowSelection(row, false)
+	})
+}
+
+
+defineExpose({
+	openDrawer,
+	clearSelection,
+	selectTableChange,
+	getProductList,
+	getStockTotalList
+})
+</script>
+
+<template>
+	<Drawer ref="drawerProductRef" :handleClose="callbackProductDrawer" size="70%">
+		<template #header="{ params }">
+			<h4 :id="params.titleId" :class="params.titleClass">选择产品</h4>
+		</template>
+		<el-card class="box-card" shadow="never">
+			<template #header>
+				<div class="input-suffix">
+					<el-row :gutter="20" style="margin-bottom: 0">
+						<el-col :xl="5" :lg="8" :md="10" class="d-flex">
+							<span class="inline-flex items-center">产品分类:</span>
+							<el-select v-model="initParam.T_class" clearable placeholder="请选择分类~">
+								<el-option v-for="item in classOptions" :key="item.Id" :label="item.T_name"
+										   :value="item.Id"/>
+							</el-select>
+						</el-col>
+						<el-col :xl="7" :lg="8" :md="10" class="d-flex">
+							<span class="inline-flex items-center">产品名称:</span>
+							<el-select
+								v-model="autoSelect"
+								filterable
+								clearable
+								remote
+								reserve-keyword
+								placeholder="按产品名称搜索"
+								remote-show-suffix
+								:remote-method="querySearchAsync"
+								:loading="loading"
+								@change="handleSelect"
+							>
+								<el-option v-for="item in NameOptions" :key="item.value" :label="item.value"
+										   :value="item.value"/>
+							</el-select>
+						</el-col>
+						<el-col :xl="7" :lg="8" :md="12" class="d-flex">
+							<span class="inline-flex items-center">产品型号:</span>
+							<el-select v-model="initParam.T_model" clearable placeholder="请选择型号~">
+								<el-option v-for="item in modelOptions" :key="item.index" :label="item.value"
+										   :value="item.value"/>
+							</el-select>
+							<el-button type="primary" @click="searchModelHandle">搜索</el-button>
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+			<el-table
+				ref="selectTable"
+				:row-key="getRowKey"
+				:data="productList"
+				style="width: 100%; height: 99%"
+				:header-cell-style="{
+          background: '#dedfe0',
+          height: '50px'
+        }"
+				v-el-table-infinite-scroll="load"
+				:infinite-scroll-immediate="false"
+				infinite-scroll-distance="'50px'"
+				@select="ProductselectionChange"
+				@select-all="ProductSelectionAllChange"
+			>
+				<template v-for="item in productColumns" :key="item">
+					<el-table-column v-if="item.type === 'index' || item.type === 'selection'" align="center"
+									 v-bind="item"/>
+					<el-table-column show-overflow-tooltip v-if="!item.ellipsis && item.prop" v-bind="item">
+						<template #default="{ row }">
+							<el-input
+								v-if="item.prop === 'count' && row.T_product_relation_sn !== 1"
+								v-model.number="row.count"
+								type="text"
+								autocomplete="off"
+								@blur="countBlurHandle"
+							/>
+							  <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>
+							  </span>
+
+							<span v-if="item.prop === 'T_occupy'">
+								<el-text v-if="row.T_occupy > 0" type="danger">{{row.T_occupy}}</el-text>
+								<el-text v-else type="info">{{row.T_occupy}}</el-text>
+							  </span>
+							<ImageCom v-if="item.prop === 'T_img'" :src="row.T_img"/>
+						</template>
+					</el-table-column>
+					<el-table-column show-overflow-tooltip v-if="item.ellipsis && item.prop === 'T_model'"
+									 align="center" 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 show-overflow-tooltip v-if="item.ellipsis && item.prop === 'T_remark'"
+									 align="center" v-bind="item">
+						<template #default="{ row }">
+							<el-tooltip effect="customized" placement="left">
+								<template #content>
+									<div class="tooltip-content">{{ row.T_remark }}</div>
+								</template>
+								{{ row.T_remark }}
+							</el-tooltip>
+						</template>
+					</el-table-column>
+				</template>
+			</el-table>
+		</el-card>
+	</Drawer>
+</template>
+
+<style scoped lang="scss">
+.tooltip-content {
+	max-width: 500px;
+	overflow-y: auto;
+}
+
+.box-card {
+	height: 100%;
+
+	:deep(.el-card__body) {
+		height: calc(100% - 70px);
+	}
+
+	.sn-header {
+		display: flex;
+		justify-content: end;
+	}
+
+	.input-suffix {
+		width: 100%;
+
+		.inline-flex {
+			white-space: nowrap;
+		}
+
+		.d-flex {
+			display: flex;
+		}
+	}
+}
+</style>

+ 395 - 0
src/views/storehouse/outStock/outStockApply/modules/OutStorageWarehouse.vue

@@ -0,0 +1,395 @@
+<script setup lang="ts">
+import type {FormInstance, FormRules} from 'element-plus'
+import {ElMessage} from 'element-plus'
+import OutStorageEditSn from './OutStorageEditSn.vue'
+import {nextTick, reactive, ref} from 'vue'
+import {GlobalStore} from '@/stores/index'
+import Drawer from '@/components/Drawer/index.vue'
+import {InStoreageFormTypes} from '@/hooks/useDepot'
+import OutStorageProduct from './OutStorageProduct.vue'
+import {CirclePlus, Delete} from '@element-plus/icons-vue'
+import {
+	Storehouse_StockOut_Get,
+	Storehouse_StockOut_Warehouse
+} from '@/api/storehouse/index'
+import ImageCom from '@/components/Image/index.vue'
+import {paymentMethodOptions} from "@/hooks/useTablePublic";
+
+
+const tableData = ref<any[]>([])
+const globalStore = GlobalStore()
+const formLabelWidth = ref('120px')
+const ruleFormRef = ref<FormInstance>()
+const drawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+const drawerSnEditRef = ref<InstanceType<typeof OutStorageEditSn> | null>(null)
+const drawerProductRef = ref<InstanceType<typeof OutStorageProduct> | null>(null)
+
+const form = reactive<InStoreageFormTypes>({
+	T_number: '',
+	T_depot_id: '',
+	T_product: '',//明细拼接
+	T_project: '',//关联项目
+	T_date: '',
+	T_receive: '',
+	T_receive_name: '',
+	T_remark: '',
+	T_company_name: '',
+	T_payment_method: '',
+});
+
+const validate_T_product = (rule: any, value: any, callback: any) => {
+	console.log("验证产品",value)
+	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_depot_id: [{required: true, message: '请选择仓库', trigger: 'blur'}],
+	T_date: [{required: true, message: '请选择出库日期', trigger: 'blur'}]
+})
+
+const columns = [
+	{type: 'index', label: '序号', width: 80, align: 'center '},
+	{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_number', 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'},
+	{label: '*关联设备', prop: 'sn', align: 'center ', name: 'sn'},
+	{prop: 'operation', label: '操作', width: 80, fixed: 'right'}
+]
+
+const countBlurHandle = () => {
+	form.T_product = tableData.value.map(item => {
+		if (!item.count && item.T_relation_sn !== 1) return undefined
+		return `${item.T_product_id},${item.count}|`
+	})
+}
+const getDeviceSnToProduct = () => {
+	const DeviceSnData: any = drawerSnEditRef.value?.getDeviceSn()
+	const isEmpty = determineSNorCount(DeviceSnData)
+	if (isEmpty && isEmpty === 'count') return [undefined]
+	if (isEmpty && isEmpty === 'sn') return [null]
+	let arr = [...tableData.value]
+	let mapArr: any = []
+	let flag = false
+	for (const item of arr) {
+		if (item.count == 0) {
+			flag = true
+			break;
+		}
+		mapArr.push(item.T_product_id + '-' + item.count + '-' + (item.T_device_list ? item.T_device_list.join(',') : ''))
+	}
+	return flag ? undefined : mapArr.join('|') + '|'
+}
+/**
+ * 判断sn or 数量是否为空
+ */
+const determineSNorCount = (DeviceSnData: any) => {
+	for (const item of tableData.value) {
+		if (item.count < 1 && item.T_relation_sn !== 1) return 'count'  //数量必大于0
+		if (item.T_relation_sn === 1 && !DeviceSnData.get(item.Id) && !DeviceSnData.size) return 'sn'
+	}
+	return false
+}
+
+const AddInStorage = (formEl: FormInstance | undefined) => {
+
+	form.T_product = getDeviceSnToProduct()
+	if (!formEl) return
+	formEl.validate(async valid => {
+		if (valid) {
+			const res: any = await Storehouse_StockOut_Warehouse({
+				...form
+			})
+			if (res.Code === 200) {
+				ElMessage.success('出库成功!')
+				drawerProductRef.value?.clearSelection()
+				nextTick(() => {
+					emit('onUpdateList')
+					resetForm(ruleFormRef.value)
+					drawerRef.value?.closeDrawer()
+				})
+			}
+		}
+	})
+}
+
+const deleteProduct = (row: any) => {
+  tableData.value = tableData.value.filter(item => item.Id !== row.Id)
+
+  // 设置产品的选中
+  drawerProductRef.value?.selectTableChange(row)
+  // 删除设备得sn
+  drawerSnEditRef.value?.deleteDeviceSn(row.Id)
+}
+
+const callbackDrawer = (done: () => void) => {
+	resetForm(ruleFormRef.value)
+	done()
+}
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+	if (!formEl) return
+	drawerProductRef.value?.clearSelection()
+	drawerSnEditRef.value?.clearDeviceSn()
+	tableData.value = []
+	formEl.resetFields()
+}
+
+/**
+ * 添加产品
+ */
+const AddProductionDetailed = () => {
+	drawerProductRef.value?.openDrawer()
+	drawerProductRef.value?.getProductList()
+	// drawerProductRef.value?.getStockTotalList(form.T_depot_id)
+}
+/**
+ * 单选
+ */
+const ProductselectionChange = (row: any) => {
+	row.T_product_id = row.Id
+  const index = tableData.value.findIndex((item: any) => item.T_product_id === row.T_product_id)
+  if (index === -1) {
+    row.count = 0
+    tableData.value.push(row)
+  } else {
+    tableData.value.splice(index, 1)
+  }
+}
+/**
+ * 全选
+ */
+const ProductSelectionAllChange = (selection: any[]) => {
+  console.log('全选',selection)
+  let arr = [...selection]
+  arr.forEach((item:any)=>{
+    item.T_product_id = item.Id
+  })
+  tableData.value = selection
+}
+
+
+const getStorehouseContractGet = async (Id: any) => {
+	const res: any = await Storehouse_StockOut_Get({User_tokey: globalStore.GET_User_tokey, T_number: Id})
+	if (res.Code === 200) {
+		let arr = res.Data.T_Product
+		arr.forEach((item: any) => {
+			tableData.value.push({
+				Id: item.Id,
+				T_class_name: item.T_product_class_name,
+				T_img: item.T_product_img,
+				T_model: item.T_number,
+				T_name: item.T_product_name,
+				count: item.T_num,
+				T_relation_sn: item.T_product_relation_sn,
+				T_spec: item.T_product_spec,
+				T_device_list: item.T_device_list,
+				T_product_id: item.T_product_id
+			})
+		})
+	}
+}
+
+/**
+ * 添加sn 号
+ */
+
+const addDeviceSn = (obj: any) => {
+	console.log("====obj",obj)
+	console.log("====drawerSnEditRef",drawerSnEditRef.value)
+	drawerSnEditRef.value?.addDeviceSn(obj.Id, 1, obj.T_product_id)
+	drawerSnEditRef.value!.drawerSnRef?.openDrawer()
+	drawerSnEditRef.value!.snCount = obj.count
+	if (obj.T_device_list) drawerSnEditRef.value!.tableSnData = [...obj.T_device_list].map(item => ({sn: item}));
+}
+/**
+ * 自动计算 count
+ */
+const autoGetCount = (length: number, id: number, arr: any) => {
+	tableData.value.forEach((item: any) => {
+		if (item.Id === id)  {
+			// 判断出库数量与扫码数量是否一致
+			if (item.count !== length) {
+				ElMessage.error('出库数量与扫码数量不一致')
+				return
+			}
+			item.T_device_list = arr
+		}
+	})
+}
+/**
+ * 关闭 取消
+ */
+const closeInStorage = () => {
+	resetForm(ruleFormRef.value)
+	drawerRef.value?.closeDrawer()
+}
+// 注册事件
+const emit = defineEmits<{ (event: 'onUpdateList'): void }>()
+
+// 接受props
+interface ItemType {
+	T_name: string
+	Id: number
+}
+
+interface PropsType {
+	options?: ItemType[]
+}
+
+const props = defineProps<PropsType>()
+/**
+ * 出库调用
+ */
+const openDrawer = () => drawerRef.value?.openDrawer()
+
+defineExpose({
+	openDrawer, getStorehouseContractGet, form
+})
+</script>
+<template>
+	<div class="inStorage-form">
+		<Drawer ref="drawerRef" :handleClose="callbackDrawer" size="80%">
+			<template #header="{ params }">
+				<h4 :id="params.titleId" :class="params.titleClass">出库</h4>
+			</template>
+			<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" 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" :disabled="true" clearable
+							   placeholder="请选择出库仓库~">
+						<el-option v-for="item in props.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_company_name">
+					<el-input v-model="form.T_company_name" placeholder="请输入公司名称" class="w-50"/>
+				</el-form-item>
+				<el-form-item label="付款方式:" class="m-b-6" :label-width="formLabelWidth" prop="T_payment_method">
+					<el-select v-model="form.T_payment_method" class="w-50 m-2" clearable placeholder="请选择付款方式~">
+						<el-option v-for="item in paymentMethodOptions" :key="item.id" :label="item.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="width: 21.5rem"
+						v-model="form.T_date"
+						type="date"
+						placeholder="选择日期"
+						format="YYYY-MM-DD"
+						value-format="YYYY-MM-DD"
+						:clearable="false"
+					/>
+				</el-form-item>
+				<el-form-item label="关联项目:" :label-width="formLabelWidth" prop="T_project">
+					<el-input v-model="form.T_project" 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_receive_name" placeholder="请选择经办人" class="w-50"/>
+				</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 show-overflow-tooltip 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"
+										disabled="true"
+										v-model.number="row.count"
+										type="text"
+										autocomplete="off"
+										@blur="countBlurHandle"
+									/>
+									<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)"
+										>添加
+										</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>
+                  </span>
+									<ImageCom v-if="item.prop == 'T_img'" :src="row.T_img"/>
+								</template>
+							</el-table-column>
+							<el-table-column show-overflow-tooltip 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>
+						</template>
+					</el-table>
+				</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="closeInStorage">取消</el-button>
+						<el-button color="#626aef" @click="AddInStorage(ruleFormRef)">提交</el-button>
+					</el-divider>
+				</div>
+				<OutStorageEditSn ref="drawerSnEditRef" @onCount="autoGetCount"/>
+
+			</el-form>
+		</Drawer>
+		<OutStorageProduct
+			ref="drawerProductRef"
+			:depotId="form.T_depot_id"
+			:selectProductData="tableData"
+			@ontableData="ProductselectionChange"
+			@ontableDataAll="ProductSelectionAllChange"
+		/>
+
+	</div>
+</template>
+<style scoped lang="scss">
+</style>

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

@@ -26,6 +26,7 @@ interface InfoType {
   T_discount: number
   T_start_date: string
   T_end_date: string
+  T_stamping_date: string
   T_submit_name: string
   T_project: string
   T_no_recoveries_money: number
@@ -259,6 +260,12 @@ onUnmounted(() => {
             <span>{{ info?.T_end_date! }}</span></el-col
           >
         </el-row>
+		<el-row v-if="!isVerify">
+		  <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_stamping_date! }}</span></el-col
+		  >
+		</el-row>
 
         <el-row>
           <el-col :xs="8" :sm="6" :md="4" :lg="3" :xl="2"> <span>项目</span></el-col>

+ 8 - 0
src/views/storehouse/sales/VerifyContractDetail.vue

@@ -29,6 +29,8 @@ const columns: ColumnProps[] = [
   { prop: 'T_discount', label: '金额' },
   { prop: 'T_start_date', label: '起始时间' },
   { prop: 'T_end_date', label: '终止时间' },
+  { prop: 'T_stamping_date', label: '盖章时间' },
+  { prop: 'T_payment_method', label: '付款方式' , name: 'T_payment_method' },
   { prop: 'T_verify_state', label: '是否过期', name: 'T_verify_state' },
   { prop: 'operation', label: '操作', width: 260, fixed: 'right' }
 ]
@@ -80,6 +82,12 @@ onMounted(() => {
           </el-col>
         </el-row>
       </template>
+		<template #T_payment_method="{ row }">
+			<el-text v-if="row.T_payment_method === 'A'" type="info"> 先货后款 </el-text>
+			<el-text v-else-if="row.T_payment_method === 'B'" type="info"> 收部分定金50 </el-text>
+			<el-text v-else-if="row.T_payment_method === 'C'" type="info"> 先款后货 </el-text>
+			<el-text v-else>  </el-text>
+		</template>
       <template #T_verify_state="{ row }">
         <el-tag v-if="row.T_verify_state === 1" type="warning" effect="dark"> 未签约 </el-tag>
         <el-tag v-else-if="row.T_verify_state === 2" type="info" effect="dark"> 已作废 </el-tag>

+ 30 - 3
src/views/storehouse/sales/VerifyForm.vue

@@ -51,6 +51,12 @@ const rules = reactive<FormRules>({
   T_submit: [{ required: true, message: '请选择合同负责人', trigger: 'change' }]
 })
 
+const options = [
+	{name: '先货后款', id: 'A'},
+	{name: '收部分定金50%', id: 'B'},
+	{name: '先款后货', id: 'C'}
+]
+
 const callbackDrawer = (done: () => void) => {
   closeCancle()
   done()
@@ -76,10 +82,12 @@ const form:any = ref<ContractFormType>({
   T_submit_name: '',
   T_start_date: '',
   T_end_date: '',
-  T_type: '', 
+  T_stamping_date: '',
+  T_payment_method: '',
+  T_type: '',
   T_uuid_name: '',
-   T_remit: '',
-   T_approval_money: '',
+  T_remit: '',
+  T_approval_money: '',
   T_approval_opinion: '',
   T_State: ''
 })
@@ -288,9 +296,12 @@ const closeCancle = () => {
 
 const props = defineProps<{ verify_customer_id: string }>()
 
+
+
 defineExpose({
   openDrawer
 })
+
 </script>
 
 <template>
@@ -396,6 +407,22 @@ defineExpose({
             value-format="YYYY-MM-DD"
           />
         </el-form-item>
+		  <el-form-item label="盖章时间:" :label-width="formLabelWidth" prop="T_stamping_date">
+			  <el-date-picker
+				  class="my-date-picker"
+				  style="width: 21.5rem"
+				  v-model="form.T_stamping_date"
+				  type="date"
+				  placeholder="选择日期"
+				  format="YYYY-MM-DD"
+				  value-format="YYYY-MM-DD"
+			  />
+		  </el-form-item>
+		  <el-form-item label="付款方式:" class="m-b-6" :label-width="formLabelWidth" prop="T_payment_method">
+			  <el-select v-model="form.T_payment_method" class="w-50 m-2" clearable placeholder="请选择付款方式~">
+				  <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id"/>
+			  </el-select>
+		  </el-form-item>
         <el-form-item label="合同负责人:" :label-width="formLabelWidth" prop="T_submit">
           <el-input v-model="form.T_submit" placeholder="请选择合同负责人" class="w-50" @focus="selectApprover" />
         </el-form-item>

+ 63 - 8
src/views/storehouse/verifyCompany/VerifyContract.vue

@@ -1,8 +1,10 @@
 <script setup lang="ts">
 import {
-  Storehouse_VerifyContract_Add_Customer,
-  Storehouse_VerifyContract_Customer_List,
-  Storehouse_VerifyContract_Update_Customer
+	exportOperationFile,
+	Storehouse_Stock_Detail_Excel,
+	Storehouse_VerifyContract_Add_Customer,
+	Storehouse_VerifyContract_Customer_List, Storehouse_VerifyContract_Excel,
+	Storehouse_VerifyContract_Update_Customer
 } from '@/api/storehouse'
 import { useRouter } from 'vue-router'
 import { ElMessage } from 'element-plus'
@@ -84,6 +86,39 @@ const AddContract = (formEl: FormInstance | undefined) => {
     }
   })
 }
+const visible = ref(false)
+const exportExcel = () => (visible.value = true)
+const T_date_detail = ref<string[]>([])
+const confirmExport = async () => {
+
+	try {
+		const response: any = await Storehouse_VerifyContract_Excel({
+			User_tokey: globalStore.GET_User_tokey,
+			T_start_date: T_date_detail.value[0],
+			T_end_date: T_date_detail.value[1],
+			T_name: initParam.T_name,
+			T_state: initParam.T_state,
+		})
+
+		// 处理返回的二进制文件并触发下载
+		const blob = new Blob([response], {type: 'application/vnd.ms-excel;charset=utf8'})
+		const url = window.URL.createObjectURL(blob)
+		const a = document.createElement('a')
+		a.href = url
+		const now = new Date();
+		const formattedDate = `${now.getFullYear()}${(now.getMonth()+1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}`;
+		a.download = `合同明细_${formattedDate}.xlsx`;
+		document.body.appendChild(a)
+		a.click()
+		a.remove()
+		window.URL.revokeObjectURL(url)
+		ElMessage.success('导出成功')
+	} catch (error) {
+		ElMessage.error('导出失败,请检查网络连接')
+	}
+
+}
+
 </script>
 
 <template>
@@ -96,7 +131,7 @@ const AddContract = (formEl: FormInstance | undefined) => {
     >
       <template #table-header>
         <el-row :gutter="20" style="margin-bottom: 0" class="input-suffix">
-          <el-col :xl="6" :lg="8" :md="8" class="d-flex">
+          <el-col :xl="6"  :md="6" class="d-flex">
             <span class="inline-flex items-center">客户名称:</span>
             <el-input
               v-model="initParam.T_name"
@@ -106,16 +141,31 @@ const AddContract = (formEl: FormInstance | undefined) => {
               @change="searchOnTableList(TableRef)"
             />
           </el-col>
-          <el-col :xl="6" :md="8" class="d-flex">
+          <el-col :xl="10" :md="10" class="d-flex">
             <span class="inline-flex items-center">状态:</span>
             <el-select v-model="initParam.T_state" class="w-50" clearable placeholder="请选择状态~">
               <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id" />
             </el-select>
             <el-button type="primary" @click="searchOnTableList(TableRef)">搜索</el-button>
+			  <el-popover :visible="visible" placement="bottom" :width="400" trigger="click">
+				  <template #reference>
+					  <el-button type="success" @click="exportExcel">导出</el-button>
+				  </template>
+				  <el-date-picker v-model="T_date_detail" type="daterange" range-separator="~"
+								  start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD"
+								  value-format="YYYY-MM-DD" />
+				  <div class="export-popover">
+					  <el-button size="small" @click="visible = false">取消</el-button>
+					  <el-button size="small" type="primary"
+								 @click="confirmExport">确认</el-button>
+				  </div>
+			  </el-popover>
+
           </el-col>
-          <el-col :xl="6" :md="2" :offset="4" class="btn"
-            ><el-button type="primary" @click="openContract('new')">添加</el-button></el-col
-          >
+          <el-col :xl="8" :md="8"  class="btn"
+            ><el-button type="primary" @click="openContract('new')">添加</el-button>
+
+		  </el-col>
         </el-row>
       </template>
       <template #T_State="{ row }">
@@ -150,6 +200,11 @@ const AddContract = (formEl: FormInstance | undefined) => {
 
 <style scoped lang="scss">
 @import '@/styles/var.scss';
+.export-popover {
+	padding: 5px;
+	display: flex;
+	justify-content: center;
+}
 
 .verify-contract {
   @include f-direction;