|
@@ -2,17 +2,26 @@
|
|
|
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
|
|
|
} from '@/api/storehouse/index'
|
|
|
-import { ref, reactive, nextTick, onMounted } from 'vue'
|
|
|
+import { ref, reactive, onMounted } from 'vue'
|
|
|
import { List, Picture, ArrowUpBold, ArrowDownBold } from '@element-plus/icons-vue'
|
|
|
+import Drawer from '@/components/Drawer/index.vue'
|
|
|
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'
|
|
|
+
|
|
|
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)
|
|
|
|
|
|
+let timeout: NodeJS.Timeout
|
|
|
const searchShow = ref(false)
|
|
|
const initParam = reactive({
|
|
|
User_tokey: globalStore.GET_User_tokey,
|
|
@@ -21,9 +30,15 @@ const initParam = reactive({
|
|
|
T_product_name: '',
|
|
|
T_product_model: ''
|
|
|
})
|
|
|
+const detailInitParam = reactive({
|
|
|
+ T_depot_id: '',
|
|
|
+ T_product_id: '',
|
|
|
+ T_start_date: '',
|
|
|
+ T_end_date: ''
|
|
|
+})
|
|
|
const columns: ColumnProps[] = [
|
|
|
{ type: 'index', label: '序号', width: 80 },
|
|
|
- { prop: 'T_iccid', label: '仓库名称', ellipsis: true },
|
|
|
+ { 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: '产品分类' },
|
|
@@ -33,8 +48,50 @@ const columns: ColumnProps[] = [
|
|
|
{ prop: 'operation', label: '操作', width: 200, fixed: 'right' }
|
|
|
]
|
|
|
|
|
|
-const searchShowHandle = () => {
|
|
|
- searchShow.value = !searchShow.value
|
|
|
+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: '期末库存' }
|
|
|
+]
|
|
|
+
|
|
|
+const searchShowHandle = () => (searchShow.value = !searchShow.value)
|
|
|
+const searchHandle = () => {
|
|
|
+ TableRef.value?.searchTable()
|
|
|
+}
|
|
|
+const dataCallback = (res: any) => {
|
|
|
+ return res.Data.Data.map((item: any) => {
|
|
|
+ depotOptions.value.forEach((depot: any) => {
|
|
|
+ if (item.T_depot_id === depot.Id) {
|
|
|
+ item.T_depot_name = depot.T_name
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return item
|
|
|
+ })
|
|
|
+}
|
|
|
+const detailDataCallback = (res: any) => res.Data
|
|
|
+/**
|
|
|
+ * 导出表格
|
|
|
+ */
|
|
|
+const T_date = ref<string[]>([]) // 作为初始值
|
|
|
+const T_date_detail = ref<string[]>([])
|
|
|
+const T_date_export = ref<string[]>([])
|
|
|
+const visible = ref(false)
|
|
|
+const exportExcel = () => (visible.value = true)
|
|
|
+const confirmExpor = async () => {
|
|
|
+ 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]
|
|
|
+ }
|
|
|
+ const res = await Storehouse_Stock_Detail_Excel(params)
|
|
|
+ console.log(res)
|
|
|
}
|
|
|
|
|
|
// 拿到仓库列表
|
|
@@ -42,43 +99,166 @@ interface ItemType {
|
|
|
T_name: string
|
|
|
Id: number
|
|
|
}
|
|
|
-const options = ref<ItemType[]>([])
|
|
|
+const depotOptions = ref<ItemType[]>([])
|
|
|
+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 getDepotList = async () => {
|
|
|
- if (globalStore.GET_depotList.length) return
|
|
|
+ if (globalStore.GET_depotList.length) {
|
|
|
+ depotOptions.value = globalStore.GET_depotList
|
|
|
+ return
|
|
|
+ }
|
|
|
const res: any = await Storehouse_Depot_List({ User_tokey: globalStore.GET_User_tokey, page: 1, page_z: 999 })
|
|
|
- options.value = res.Data.Data
|
|
|
- globalStore.SET_depotList(options.value)
|
|
|
+ depotOptions.value = res.Data.Data
|
|
|
+ globalStore.SET_depotList(depotOptions.value)
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 模糊搜索名称
|
|
|
+ * @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
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 模糊搜索名称
|
|
|
+ * @param queryString 输入框的输入字符
|
|
|
+ * @param cb 异步搜索后的回调
|
|
|
+ */
|
|
|
+const querySearchAsync = async (queryString: string, cb: (arg: any) => void) => {
|
|
|
+ clearTimeout(timeout)
|
|
|
+ globalStore.SET_isloading(true)
|
|
|
+ timeout = setTimeout(async () => {
|
|
|
+ const results = await getNameAsync(queryString)
|
|
|
+ cb(results)
|
|
|
+ globalStore.SET_isloading(false)
|
|
|
+ }, 2000)
|
|
|
+}
|
|
|
+/**
|
|
|
+ * 异步获取产品型号
|
|
|
+ */
|
|
|
+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)
|
|
|
+}
|
|
|
+const handleSelect = (item: any) => {
|
|
|
+ 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()
|
|
|
+}
|
|
|
+const dateDetailChange = (str: string[]) => {
|
|
|
+ if (!str) return
|
|
|
+ detailInitParam.T_start_date = str[0]
|
|
|
+ detailInitParam.T_end_date = str[1]
|
|
|
+ TableDetailRef.value?.searchTable()
|
|
|
}
|
|
|
onMounted(() => {
|
|
|
getDepotList()
|
|
|
+ getProductClassList()
|
|
|
+
|
|
|
+ T_date.value = [dayJs().startOf('year').format('YYYY-MM-DD'), dayJs().format('YYYY-MM-DD')]
|
|
|
+ T_date_export.value = [...T_date.value]
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
<template>
|
|
|
<div class="inventory-statistics">
|
|
|
- <TableBase ref="TableRef" :columns="columns" :requestApi="Storehouse_Stock_List" :initParam="initParam">
|
|
|
+ <TableBase
|
|
|
+ ref="TableRef"
|
|
|
+ :columns="columns"
|
|
|
+ :requestApi="Storehouse_Stock_List"
|
|
|
+ :initParam="initParam"
|
|
|
+ :dataCallback="dataCallback"
|
|
|
+ >
|
|
|
<template #table-header>
|
|
|
<div class="head-search" :class="searchShow ? 'active' : ''">
|
|
|
<el-form :model="initParam" class="result-form" label-width="100px">
|
|
|
<el-row>
|
|
|
<el-col :span="6"
|
|
|
- ><el-form-item label="产品分类" :inline-message="true"> <el-input /> </el-form-item
|
|
|
+ ><el-form-item label="产品分类" :inline-message="true">
|
|
|
+ <el-select v-model="initParam.T_product_class" class="w-50 m-2" clearable placeholder="请选择分类~">
|
|
|
+ <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="6"
|
|
|
- ><el-form-item label="产品名称"> <el-input /> </el-form-item
|
|
|
+ ><el-form-item label="产品名称">
|
|
|
+ <el-autocomplete
|
|
|
+ v-model="initParam.T_product_name"
|
|
|
+ clearable
|
|
|
+ :fetch-suggestions="querySearchAsync"
|
|
|
+ placeholder="按产品名称搜索"
|
|
|
+ :debounce="2000"
|
|
|
+ :trigger-on-focus="false"
|
|
|
+ @select="handleSelect"
|
|
|
+ /> </el-form-item
|
|
|
></el-col>
|
|
|
<el-col :span="6"
|
|
|
- ><el-form-item label="产品型号"> <el-input /> </el-form-item
|
|
|
+ ><el-form-item label="产品型号">
|
|
|
+ <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-form-item
|
|
|
></el-col>
|
|
|
<el-col :span="6">
|
|
|
- <el-button :icon="ArrowDownBold" @click="searchShowHandle" />
|
|
|
- <el-button type="primary">搜索</el-button>
|
|
|
- <el-button type="success">导出</el-button>
|
|
|
+ <el-button :icon="searchShow ? ArrowUpBold : ArrowDownBold" @click="searchShowHandle" />
|
|
|
+ <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-row class="search-bottom">
|
|
|
<el-col :span="6"
|
|
|
- ><el-form-item label="仓库列表" :inline-message="true"> <el-input /> </el-form-item
|
|
|
+ ><el-form-item label="仓库列表" :inline-message="true">
|
|
|
+ <el-select v-model="initParam.T_depot_id" class="w-50 m-2" clearable placeholder="请选择分类~">
|
|
|
+ <el-option v-for="item in depotOptions" :key="item.Id" :label="item.T_name" :value="item.Id" />
|
|
|
+ </el-select> </el-form-item
|
|
|
></el-col>
|
|
|
</el-row>
|
|
|
</el-form>
|
|
@@ -100,19 +280,59 @@ onMounted(() => {
|
|
|
</el-image>
|
|
|
</template>
|
|
|
<template #right="{ row }">
|
|
|
- <el-button link type="primary" size="small" :icon="List">明细</el-button>
|
|
|
+ <el-button link type="primary" size="small" :icon="List" @click="previewDetail(row.T_product_id)"
|
|
|
+ >明细</el-button
|
|
|
+ >
|
|
|
</template>
|
|
|
</TableBase>
|
|
|
+ <Drawer ref="DrawerRef" :handleClose="callbackDrawer" size="80%">
|
|
|
+ <template #header="{ params }">
|
|
|
+ <h4 :id="params.titleId" :class="params.titleClass">库存明细</h4>
|
|
|
+ </template>
|
|
|
+ <TableBase
|
|
|
+ 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-row>
|
|
|
+ </template>
|
|
|
+ </TableBase>
|
|
|
+ </Drawer>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<style scoped lang="scss">
|
|
|
@import '@/styles/var.scss';
|
|
|
+.export-popover {
|
|
|
+ padding: 5px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+}
|
|
|
+:deep(.drawer__content) {
|
|
|
+ @include f-direction;
|
|
|
+}
|
|
|
.inventory-statistics {
|
|
|
@include f-direction;
|
|
|
.head-search {
|
|
|
width: 100%;
|
|
|
- height: 32px;
|
|
|
+ height: 33px;
|
|
|
overflow: hidden;
|
|
|
transition: all 0.5s ease-in-out;
|
|
|
.result-form.el-form .el-form-item {
|
|
@@ -123,7 +343,7 @@ onMounted(() => {
|
|
|
}
|
|
|
}
|
|
|
.head-search.active {
|
|
|
- height: 82px;
|
|
|
+ height: 85px;
|
|
|
}
|
|
|
.image-slot {
|
|
|
display: flex;
|