YangJian0701 10 сар өмнө
parent
commit
2e7db11c7f

+ 1 - 1
.editorconfig

@@ -5,7 +5,7 @@ charset = utf-8 # 设置文件字符集为 utf-8
 end_of_line = lf # 控制换行类型(lf | cr | crlf)
 insert_final_newline = true # 始终在文件末尾插入一个新行
 indent_style = tab # 缩进风格(tab | space)
-indent_size = 2 # 缩进大小
+indent_size = 4 # 缩进大小
 max_line_length = 120 # 最大行长度
 
 [*.md] # 表示仅对 md 文件适用以下规则

BIN
ERP.rar


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

@@ -104,6 +104,10 @@ export const Storehouse_Device_List = (params: any) => $http.post('/storage/Devi
  */
 // 入库列表
 export const Storehouse_StockIn_List = (params: any) => $http.post('/storage/StockIn/List', params)
+
+// 入库明细
+export const StockIn_ListProducts = (params: any) => $http.post('/storage/StockIn/List_Product', params)
+
 // 详情
 export const Storehouse_StockIn_Get = (params: any) => $http.post('/storage/StockIn/Get', params)
 // 入库
@@ -114,6 +118,9 @@ export const Storehouse_StockIn_Add = (params: any) => $http.post('/storage/Stoc
  */
 // 出库列表
 export const Storehouse_StockOut_List = (params: any) => $http.post('/storage/StockOut/List', params)
+
+// 出库明细
+export const Storehouse_StockOut_ListProduct = (params: any) => $http.post('/storage/StockOut/List_Product', params)
 // 出库
 export const Storehouse_StockOut_Add = (params: any) => $http.post('/storage/StockOut/Add', params)
 // 详情

+ 3 - 1
src/hooks/useDepot.ts

@@ -29,6 +29,7 @@ export interface ReceiveFormType {
   T_type: number
   T_uuid: string
   T_receive: string
+  T_project:string
   T_number: string
   T_depot_id: any
   T_product: any
@@ -47,10 +48,11 @@ export interface InfoType {
   T_submit: string
   T_signer?: string
   T_signer_phone?: string
-  T_signer_date?: string
+  T_signer_date?: string  
   T_signer_unit?: string
   T_submit_name: string
   T_receive_name: string
+  T_project: string
   T_delivery_type: string
   T_courier_number?: number
 }

+ 1 - 1
src/views/project/ProjectFinance.vue

@@ -39,7 +39,7 @@ const columnsProject: ColumnProps[] = [
   { prop: 'T_set_up_date', label: '立项日期' },
   { prop: 'T_end_date', label: '结束时间' },
   { prop: 'T_planning_cycle', label: '计划完成周期(工作日)', width: 125 },
-  { prop: 'T_bonus', label: '绩效总金额' },
+  { prop: 'T_Perf', label: '绩效总金额' },
   { prop: 'T_State', label: '状态', name: 'T_State', width: 120 },
   { prop: 'operation', label: '操作', width: 160, fixed: 'right' }
 ]

+ 263 - 295
src/views/storehouse/InventoryStatistics.vue

@@ -1,12 +1,12 @@
 <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
+    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
 } from '@/api/storehouse/index'
 import { ref, reactive, onMounted } from 'vue'
 import { List } from '@element-plus/icons-vue'
@@ -19,8 +19,8 @@ import ImageCom from '@/components/Image/index.vue'
 import { useTablePublic } from '@/hooks/useTablePublic'
 
 const userInfo = ref({
-  Id: '',
-  T_name: ''
+    Id: '',
+    T_name: ''
 })
 const loading = ref(false)
 const globalStore = GlobalStore()
@@ -31,52 +31,52 @@ 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_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: '库存数量' },
-  { prop: 'operation', label: '操作', width: 80, fixed: 'right' }
+    { type: 'index', label: '序号', width: 80 },
+    { prop: 'T_depot_name', label: '仓库名称' },
+    { 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: '库存数量' },
+    { 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: '期末库存' }
+    { 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: '期末库存' }
 ]
 
 const searchHandle = () => {
-  TableRef.value?.searchTable()
+    TableRef.value?.searchTable()
 }
 const dataCallback = (res: any) => {
-  return res.Data.Data.map((item: any) => {
-    if (item.T_depot_id === userInfo.value.Id) {
-      item.T_depot_name = userInfo.value.T_name
-    }
-    return item
-  })
+    return res.Data.Data.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
 /**
@@ -88,315 +88,283 @@ const T_date_export = ref<string[]>([])
 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.value[0],
-    T_end_date: T_date.value[1],
-    T_product_id: ''
-  }
-  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.value[0],
+        T_end_date: T_date.value[1],
+        T_product_id: ''
+    }
+    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()
+    getProductClassList()
 
-  T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
-  T_date_export.value = [...T_date.value]
+    T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
+    T_date_export.value = [...T_date.value]
 })
 
 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)
 }
 </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-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-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_export"
-                        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 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_export" 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_product_img="{ row }">
+                        <ImageCom :src="row.T_product_img" />
+                    </template>
+                    <template #right="{ row }">
+                        <el-button link type="primary" size="small" :icon="List"
+                            @click="previewDetail(row.T_product_id)">明细</el-button>
+                    </template>
+                </TableBase>
             </div>
-          </template>
-          <template #T_product_img="{ row }">
-            <ImageCom :src="row.T_product_img" />
-          </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>
+        </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="日期范围">
-                <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>
-      </TableBase>
-    </Drawer>
-  </div>
+        <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>
+            </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;
-  .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;
-  }
-  .inventory-table {
-    @include f-direction;
-    z-index: 1;
-  }
-  .project-container {
-    @include f-direction;
-    z-index: 0;
-    margin-left: 12px;
-    width: calc(100% - 290px);
-  }
-  .head-search {
-    width: 100%;
-    height: 33px;
+    height: 100%;
+    display: flex;
     overflow: hidden;
-    transition: all 0.5s ease-in-out;
-    .result-form.el-form .el-form-item {
-      margin-bottom: 0 !important;
+
+    .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;
+    }
+
+    .inventory-table {
+        @include f-direction;
+        z-index: 1;
     }
-    .search-bottom {
-      margin-top: 18px;
+
+    .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;
+
+        .result-form.el-form .el-form-item {
+            margin-bottom: 0 !important;
+        }
+
+        .search-bottom {
+            margin-top: 18px;
+        }
+    }
+
+    .head-search.active {
+        height: 85px;
+    }
+
+    .w-50 {
+        flex: 0 0 50%;
     }
-  }
-  .head-search.active {
-    height: 85px;
-  }
-  .w-50 {
-    flex: 0 0 50%;
-  }
 }
 </style>

+ 9 - 2
src/views/storehouse/inventory/Device.vue

@@ -5,6 +5,8 @@ import TableBase from '@/components/TableBase/index.vue'
 import { Storehouse_Device_List } from '@/api/storehouse/index'
 import type { ColumnProps } from '@/components/TableBase/interface/index'
 import ImageCom from '@/components/Image/index.vue'
+import btnview from './modules/btnview.vue'
+
 
 const globalStore = GlobalStore()
 const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
@@ -13,7 +15,8 @@ const columns: ColumnProps[] = [
   { type: 'index', label: '序号', width: 80 },
   { prop: 'T_contract_number', label: '合同编号', ellipsis: true },
   { prop: 'T_out_number', label: '出库单号', ellipsis: true },
-  { prop: 'T_product_img', label: '产品图片', name: 'T_product_img' },
+  // { prop: 'T_product_img', label: '产品图片', name: 'T_product_img' },
+  { prop: 'T_project', label: '关联项目'},
   { prop: 'T_product_name', label: '产品名称' },
   { prop: 'T_product_class_name', label: '产品分类' },
   { prop: 'T_product_model', label: '产品型号', ellipsis: true },
@@ -21,7 +24,8 @@ const columns: ColumnProps[] = [
   { prop: 'T_sn', label: '设备SN', ellipsis: true },
   { prop: 'T_imei', label: '模组imei', ellipsis: true },
   { prop: 'T_iccid', label: '物联网卡号', ellipsis: true },
-  { prop: 'T_State', label: '状态', name: 'T_State' }
+  { prop: 'T_State', label: '状态', name: 'T_State' },
+  { prop: 'operation', label: '操作', width: 260, fixed: 'right' }
 ]
 
 // 搜索
@@ -72,6 +76,9 @@ const searchHandle = () => {
       <template #T_product_img="{ row }">
         <ImageCom :src="row.T_product_img" />
       </template>
+      <template #right="{ row }">
+        <btnview :btnData="row"></btnview>
+      </template>
     </TableBase>
   </div>
 </template>

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

@@ -39,6 +39,9 @@ const addSn = (formEl: FormInstance | undefined) => {
       const res: any = await Storehouse_Device_Check({ T_sn: formSn.sn, T_type: formSn.type })
       if (res.Code === 200) {
         tableSnData.value.push({ sn: formSn.sn })
+        tableSnData.value = tableSnData.value.filter((value, index, self) => {  //去重
+            return self.findIndex(t => (t.sn === value.sn)) === index;  
+        });  
         nextTick(() => {
           resetSnForm(ruleSnFormRef.value)
         })
@@ -96,7 +99,7 @@ defineExpose({
         <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" class="w-50" />
+              <el-input v-model="formSn.sn" type="text" placeholder="请输入SN" @keyup.enter="addSn(ruleSnFormRef)"   class="w-50" />
             </el-form-item>
           </el-form>
           <el-button type="primary" @click="addSn(ruleSnFormRef)">添加</el-button>

+ 137 - 0
src/views/storehouse/inventory/inStorageDetails.vue

@@ -0,0 +1,137 @@
+<script setup lang="ts">
+import { useRouter } from 'vue-router'
+import { GlobalStore } from '@/stores/index'
+import { View } from '@element-plus/icons-vue'
+import { ref, reactive } from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type { ColumnProps } from '@/components/TableBase/interface/index'
+import { StockIn_ListProducts } from '@/api/storehouse/index'
+import { depotHooks } from '@/hooks/useDepot'
+
+const router = useRouter()
+const globalStore = GlobalStore()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+
+const columns: ColumnProps[] = [
+    { type: 'index', label: '序号', width: 80 },
+    { prop: 'T_number', label: '入库单号' },
+    { prop: 'T_submit_name', label: '经办人' },
+    { prop: 'T_date', label: '入库日期' },
+    { prop: 'T_depot_name', label: '入库仓库' },
+
+    { prop: 'T_product_name', label: '产品名称' },
+    { prop: 'T_product_model', label: '产品型号' },
+    { prop: 'T_num', label: '数量' },
+
+    { prop: 'T_product_relation_sn', label: '是否关联SN', name: 'T_product_relation_sn' },
+    { prop: 'T_remark', label: '备注' },
+
+    { prop: 'operation', label: '操作', width: 260, fixed: 'right' }
+]
+
+/**
+ * 查看详情
+ */
+const dialogTableVisible = ref(false)
+const gridData:any = ref([])
+const preview = (list:any) => {
+    let arr = [...list] || []
+    gridData.value = arr.map((item:any)=>({sn:item}))
+    dialogTableVisible.value = true
+}
+// 搜索
+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: '',
+})
+
+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()
+</script>
+
+<template>
+    <div class="inStorageDetails">
+        <TableBase ref="TableRef" :columns="columns" :requestApi="StockIn_ListProducts"
+            :initParam="initParam">
+            <template #table-header>
+                <div class="input-suffix">
+                    <el-row :gutter="20" style="margin-bottom: 0">
+                        <el-col :xl="6" :lg="6" :md="6" style="display: flex">
+                            <span class="inline-flex items-center">关键字:</span>
+                            <el-input v-model="initParam.T_name" placeholder="入库单号,备注搜索" />
+                        </el-col>
+                        <el-col :xl="6" :lg="6" :md="6" style="display: flex">
+                            <span class="inline-flex items-center">入库日期:</span>
+                            <el-date-picker v-model="T_date" type="daterange" range-separator="~"
+                                start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD"
+                                value-format="YYYY-MM-DD" />
+                        </el-col>
+                        <el-col :xl="6" :lg="6" :md="6" style="display: flex">
+                            <span class="inline-flex items-center">仓库:</span>
+                            <el-select v-model="initParam.T_depot_id" clearable placeholder="请选择仓库~">
+                                <el-option v-for="item in options" :key="item.Id" :label="item.T_name"
+                                    :value="item.Id" />
+                            </el-select>
+                            <el-button type="primary" @click="searchHandle">搜索</el-button>
+                        </el-col>
+                    </el-row>
+                </div>
+            </template>
+            <template #T_product_relation_sn="{ row }">
+                <el-text class="mx-1" :type="row.T_product_relation_sn==1?'primary':'danger'">
+                    {{row.T_product_relation_sn==1?'是':'否'}}
+                </el-text>
+            </template>
+            <template #right="{ row }">
+                <el-button type="primary" size="small" v-show="row.T_product_relation_sn == 1" :icon="View"
+                    @click="preview(row.T_device_list)">查看SN</el-button>
+            </template>
+        </TableBase>
+        <el-dialog v-model="dialogTableVisible" title="查看SN" draggable>
+            <el-table :data="gridData" border max-height="500">
+                <el-table-column type="index" label="序号" width="100" />
+                <el-table-column property="sn" label="SN" />
+            </el-table>
+        </el-dialog>
+    </div>
+</template>
+
+<style scoped lang="scss">
+@import '@/styles/var.scss';
+
+.inStorageDetails {
+    @include f-direction;
+
+    .input-suffix {
+        width: 100%;
+
+        .inline-flex {
+            white-space: nowrap;
+        }
+
+        .w-50 {
+            width: 12.5rem;
+        }
+
+        .btn {
+            display: flex;
+            justify-content: end;
+
+            .el-button {
+                padding: 0 20px;
+            }
+        }
+    }
+}
+</style>

+ 55 - 0
src/views/storehouse/inventory/modules/btnview.vue

@@ -0,0 +1,55 @@
+<!--  -->
+<template>
+    <div class="">
+        <el-button type="primary" size="small" @click="showdialog">查看</el-button>
+        <el-dialog v-model="dialogTableVisible" title="查看" draggable :append-to-body="true">
+            <el-tabs v-model="activeName" class="demo-tabs">
+                <el-tab-pane :label="item.label" :name="item.name" v-for="item,index in data.tabLabel" :key="index">
+                    <tables :gridData="data.gridData"></tables>
+                </el-tab-pane>
+            </el-tabs>
+        </el-dialog>
+    </div>
+</template>
+
+<script setup lang="ts">
+import { ref,reactive,watch} from "vue";
+import type { TabsPaneContext } from 'element-plus'
+import tables from "./tables.vue";
+const dialogTableVisible = ref(false)
+const activeName = ref('first')
+const data:any = reactive({
+    gridData: [],
+    tabLabel:[
+        {label:'出入库记录',name:'first'},
+        {label:'关联项目记录',name:'second'}
+    ]
+})
+const props = defineProps({
+    btnData:{
+        type:Object,
+        default: () => {},
+    }
+})
+watch(()=>activeName.value,(newData)=>{
+    handleClick()
+})
+//函数
+const showdialog = ()=>{
+    dialogTableVisible.value = true
+    handleClick()
+}
+
+const handleClick = () => {
+  let str:any = {...props.btnData}
+  activeName.value=='first'?setJoin(str.T_remark):setJoin(str.T_project_log)
+}
+const setJoin = (str:any) => {
+    let arr = str.split('|').filter(Boolean)
+    data.gridData = arr.map((item:any) => ({name:item}))
+}
+
+</script>
+<style lang="scss">
+/* @import url(); 引入css类 */
+</style>

+ 22 - 0
src/views/storehouse/inventory/modules/tables.vue

@@ -0,0 +1,22 @@
+<template>
+    <div class="">
+        <el-table :data="gridData" :key="Math.random()" max-height="450" border>
+            <el-table-column type="index" width="80" label="序号" />
+            <el-table-column property="name" label="记录" show-overflow-tooltip/>
+        </el-table>
+    </div>
+</template>
+
+<script setup lang="ts">
+// 接受父组件参数,配置默认值
+const props = defineProps({
+    gridData: {
+        type: Array,
+        default: () => [],
+    },
+});
+</script>
+<style lang="scss">
+/* @import url(); 引入css类 */
+
+</style>

+ 1 - 0
src/views/storehouse/outStock/OutStock.vue

@@ -25,6 +25,7 @@ const columns: ColumnProps[] = [
   { prop: 'T_receive_name', label: '领取人' },
   { prop: 'T_depot_name', label: '出库仓库' },
   { prop: 'T_date', label: '出库日期' },
+  { prop: 'T_project', label: '关联项目' },
   { prop: 'T_type', label: '出库类型', name: 'T_type' },
   { prop: 'T_contract_number', label: '合同编号' },
   { prop: 'operation', label: '操作', width: 170, fixed: 'right', align: 'left ' }

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

@@ -149,6 +149,12 @@ onMounted(() => {
             ><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>

+ 4 - 0
src/views/storehouse/outStock/ReceiveOutStock.vue

@@ -25,6 +25,7 @@ const form = reactive<ReceiveFormType>({
   T_type: 1,
   T_uuid: '',
   T_receive: '',
+  T_project: '',
   T_number: '',
   T_depot_id: undefined,
   T_product: '',
@@ -236,6 +237,9 @@ const changeDepot = () => drawerProductRef.value?.clearProdctData()
           value-format="YYYY-MM-DD"
         />
       </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_receive">
         <el-input v-model="form.T_receive" placeholder="请选择经办人" class="w-50" @focus="selectApprover" />
       </el-form-item>

+ 190 - 0
src/views/storehouse/outStock/outStockDetails.vue

@@ -0,0 +1,190 @@
+<script setup lang="ts">
+import { ElMessage } from 'element-plus'
+import { useRouter } from 'vue-router'
+import { GlobalStore } from '@/stores/index'
+import { View, Van } from '@element-plus/icons-vue'
+import Drawer from '@/components/Drawer/index.vue'
+import type { FormInstance, FormRules } from 'element-plus'
+import { validate_T_phone } from '@/views/account/users/components/relus'
+import { ref, reactive, nextTick } from 'vue'
+import TableBase from '@/components/TableBase/index.vue'
+import type { ColumnProps } from '@/components/TableBase/interface/index'
+import { Storehouse_StockOut_ListProduct, Storehouse_StockOut_Edit } from '@/api/storehouse/index'
+import { depotHooks, delivery_type } from '@/hooks/useDepot'
+
+const router = useRouter()
+const formLabelWidth = ref('120px')
+const globalStore = GlobalStore()
+const ruleFormRef = ref<FormInstance>()
+const TableRef = ref<InstanceType<typeof TableBase> | null>(null)
+const DrawerRef = ref<InstanceType<typeof Drawer> | null>(null)
+
+const columns: ColumnProps[] = [
+  { type: 'index', label: '序号', width: 80 },
+  { prop: 'T_number', label: '出库单号' },
+  { prop: 'T_receive_name', label: '领取人' },
+  { prop: 'T_date', label: '出库日期' },
+  { prop: 'T_depot_name', label: '出库仓库' },
+  { prop: 'T_project', label: '关联项目' },
+  { prop: 'T_product_name', label: '产品名称', name: 'T_type' },
+  { prop: 'T_product_model', label: '产品型号' },
+  { prop: 'T_num', label: '数量' },
+
+  { prop: 'T_product_relation_sn', label: '是否关联SN', name: 'T_product_relation_sn' },
+    { prop: 'T_remark', label: '备注' },
+  { prop: 'operation', label: '操作', width: 170, 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 rules = reactive<FormRules>({
+  T_delivery_type: [{ required: true, message: '请选择送货方式', trigger: 'blur' }],
+  T_signer_unit: [{ required: true, message: '请输入签收单位', trigger: 'blur' }],
+  T_signer_phone: [{ validator: validate_T_phone, trigger: 'blur' }]
+})
+
+/**
+ * 查看详情
+ */
+ const dialogTableVisible = ref(false)
+const gridData:any = ref([])
+const preview = (list:any) => {
+    let arr = [...list] || []
+    gridData.value = arr.map((item:any)=>({sn:item}))
+    dialogTableVisible.value = true
+}
+
+// 搜索
+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: '',
+})
+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 deliveryEdit = (number: string) => {
+  form.T_number = number
+  DrawerRef.value?.openDrawer()
+}
+const callbackDrawer = (done: () => void) => done()
+const closeDrawer = () => {
+  resetForm(ruleFormRef.value)
+  DrawerRef.value?.closeDrawer()
+}
+const addOutStock = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.validate(async valid => {
+    if (valid) {
+      const res: any = await Storehouse_StockOut_Edit({ User_tokey: globalStore.GET_User_tokey, ...form })
+      if (res.Code === 200) {
+        ElMessage.success('发货成功!')
+        nextTick(() => {
+          closeDrawer()
+        })
+      }
+    }
+  })
+}
+/**
+ * 重置表单
+ */
+const resetForm = (formEl: FormInstance | undefined) => {
+  if (!formEl) return
+  formEl.resetFields()
+}
+// 拿到仓库列表
+const { options } = depotHooks()
+</script>
+
+<template>
+  <div class="out-stock">
+    <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_StockOut_ListProduct" :initParam="initParam">
+      <template #table-header>
+        <div class="input-suffix">
+          <el-row :gutter="20" style="margin-bottom: 0">
+            <el-col :xl="6" :lg="6" :md="6" style="display: flex">
+                <span class="inline-flex items-center">关键字:</span>
+                <el-input v-model="initParam.T_name" placeholder="出库单号,关联项目搜索" />
+            </el-col>
+            <el-col :xl="6" :lg="9" :md="11" style="display: flex">
+              <span class="inline-flex items-center">出库日期:</span>
+              <el-date-picker
+                v-model="T_date"
+                type="daterange"
+                range-separator="~"
+                start-placeholder="开始时间"
+                end-placeholder="结束时间"
+                format="YYYY-MM-DD"
+                value-format="YYYY-MM-DD"
+              />
+            </el-col>
+            <el-col :xl="6" :lg="7" :md="9" style="display: flex">
+              <span class="inline-flex items-center">仓库:</span>
+              <el-select v-model="initParam.T_depot_id" clearable placeholder="请选择仓库~">
+                <el-option v-for="item in options" :key="item.Id" :label="item.T_name" :value="item.Id" />
+              </el-select>
+              <el-button type="primary" @click="searchHandle">搜索</el-button>
+            </el-col>
+          </el-row>
+        </div>
+      </template>
+      <template #T_product_relation_sn="{ row }">
+            <el-text class="mx-1" :type="row.T_product_relation_sn==1?'primary':'danger'">
+                {{row.T_product_relation_sn==1?'是':'否'}}
+            </el-text>
+        </template>
+      <template #right="{ row }">
+        <el-button type="primary" size="small" v-show="row.T_product_relation_sn == 1" :icon="View"
+                    @click="preview(row.T_device_list)">查看SN</el-button>
+      </template>
+    </TableBase>
+    <el-dialog v-model="dialogTableVisible" title="查看SN" draggable>
+        <el-table :data="gridData" border max-height="500">
+            <el-table-column type="index" label="序号" width="100" />
+            <el-table-column property="sn" label="SN" />
+        </el-table>
+    </el-dialog>
+  </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: center;
+    .el-button {
+      padding: 0 20px;
+    }
+  }
+}
+</style>