feat:出入库明细模块

main
黄伟杰 1 month ago
parent 9b6536405d
commit 32acd2f31b

@ -2,15 +2,28 @@ import request from '@/config/axios'
// ERP 产品库存明细 VO // ERP 产品库存明细 VO
export interface StockRecordVO { export interface StockRecordVO {
id: number // 编号 id: number
productId: number // 产品编号 productId: number
warehouseId: number // 仓库编号 bizDirection?: string
count: number // 出入库数量 bizDocType?: number
totalCount: number // 总库存量 categoryType?: number
bizType: number // 业务类型 warehouseId: number
bizId: number // 业务编号 areaId?: number
bizItemId: number // 业务项编号 areaName?: string
bizNo: string // 业务单号 count: number
totalCount: number
bizType: number
bizId: number
bizItemId: number
bizNo: string
createTime?: string
creator?: string
productName: string
categoryName: string
unitName: string
warehouseName: string
creatorName: string
recordTime?: string
} }
// ERP 产品库存明细 API // ERP 产品库存明细 API

@ -111,7 +111,12 @@
<!-- 列表 --> <!-- 列表 -->
<ContentWrap> <ContentWrap>
<el-tabs v-model="activeName" @tab-click="handleTabClick"> <el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane v-for="item in categoryTabs" :key="item.id" :label="item.name" :name="String(item.id)" /> <el-tab-pane
v-for="item in categoryTabs"
:key="String(item.value)"
:label="item.label"
:name="String(item.value)"
/>
</el-tabs> </el-tabs>
<el-table <el-table
@ -123,48 +128,54 @@
@selection-change="handleSelectionChange" @selection-change="handleSelectionChange"
> >
<el-table-column width="30" :label="t('action.select')" type="selection" /> <el-table-column width="30" :label="t('action.select')" type="selection" />
<el-table-column :label="t('ErpStock.Record.productName')" align="left" sortable prop="productName" width="210px" /> <el-table-column :label="t('ErpStock.Record.id')" align="center" prop="id" width="100" sortable />
<el-table-column :label="t('ErpStock.Record.categoryName')" align="center" prop="categoryName" sortable /> <el-table-column :label="t('ErpStock.Record.bizDirection')" align="center" prop="bizDirection" min-width="90" sortable>
<el-table-column :label="t('ErpStock.Record.unitName')" align="center" prop="unitName" sortable />
<el-table-column :label="t('ErpStock.Record.warehouseName')" align="center" prop="warehouseName" sortable />
<el-table-column :label="t('ErpStock.Record.bizType')" align="center" prop="bizType" min-width="100" sortable>
<template #default="scope"> <template #default="scope">
<dict-tag :type="DICT_TYPE.ERP_STOCK_RECORD_BIZ_TYPE" :value="scope.row.bizType" /> <el-tag v-if="scope.row.bizDirection" :type="getDirectionTagType(scope.row.bizDirection)">
{{ scope.row.bizDirection || '-' }}
</el-tag>
<span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="t('ErpStock.Record.bizNo')" align="center" prop="bizNo" width="200" sortable /> <el-table-column :label="t('ErpStock.Record.categoryType')" align="center" prop="bizDocType" min-width="120" sortable />
<el-table-column :label="t('ErpStock.Record.productName')" align="center" sortable prop="productName" min-width="160" />
<el-table-column :label="t('ErpStock.Record.categoryName')" align="center" prop="categoryName" min-width="120" sortable />
<el-table-column :label="t('ErpStock.Record.warehouseName')" align="center" prop="warehouseName" min-width="140" sortable />
<el-table-column :label="t('ErpStock.Record.areaName')" align="center" prop="areaName" min-width="120" sortable />
<el-table-column <el-table-column
:label="t('ErpStock.Record.count')" :label="t('ErpStock.Record.count')"
align="right" align="center"
sortable sortable
prop="count" prop="count"
width="120px" min-width="120"
:formatter="erpCountTableColumnFormatter" >
/> <template #default="scope">
<span :class="getDirectionClass(scope.row.bizDirection)">
{{ formatCountWithUnit(scope.row, true) }}
</span>
</template>
</el-table-column>
<el-table-column <el-table-column
:label="t('ErpStock.Record.totalCount')" :label="t('ErpStock.Record.totalCount')"
align="right" align="center"
sortable sortable
prop="totalCount" prop="totalCount"
width="120px" min-width="120"
:formatter="erpCountTableColumnFormatter" >
/> <template #default="scope">
{{ formatCountWithUnit(scope.row) }}
</template>
</el-table-column>
<el-table-column :label="t('ErpStock.Record.bizNo')" align="center" prop="bizNo" min-width="180" sortable />
<el-table-column :label="t('ErpStock.Record.creatorName')" align="center" prop="creatorName" min-width="100" sortable />
<el-table-column <el-table-column
:label="t('ErpStock.Record.recordTime')" :label="t('ErpStock.Record.recordTime')"
align="center" align="center"
sortable sortable
prop="recordTime" prop="recordTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column
:label="t('ErpStock.Record.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter" :formatter="dateFormatter"
width="180px" width="180px"
sortable /> />
<el-table-column :label="t('ErpStock.Record.creatorName')" align="center" prop="creatorName" sortable />
</el-table> </el-table>
<!-- 分页 --> <!-- 分页 -->
<Pagination <Pagination
@ -178,28 +189,37 @@
<script setup lang="ts"> <script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import {dateFormatter, dateFormatter2} from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download' import download from '@/utils/download'
import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record' import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record'
import { ProductApi, ProductVO } from '@/api/erp/product/product' import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse' import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category' import { useDictStoreWithOut } from '@/store/modules/dict'
import { erpCountTableColumnFormatter } from '@/utils'
/** ERP 产品库存明细列表 */ /** ERP 产品库存明细列表 */
defineOptions({ name: 'ErpStockRecord' }) defineOptions({ name: 'ErpStockRecord' })
const message = useMessage() // const message = useMessage() //
const { t } = useI18n() // const { t } = useI18n() //
const dictStore = useDictStoreWithOut()
const loading = ref(true) // const loading = ref(true) //
const list = ref<StockRecordVO[]>([]) // const list = ref<StockRecordVO[]>([]) //
const total = ref(0) // const total = ref(0) //
const queryParams = reactive({ const queryParams = reactive<{
pageNo: number
pageSize: number
productId?: number
categoryType?: number
warehouseId?: number
bizType?: number
bizNo?: string
createTime: string[]
}>({
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
productId: undefined, productId: undefined,
categoryId: undefined, categoryType: undefined,
warehouseId: undefined, warehouseId: undefined,
bizType: undefined, bizType: undefined,
bizNo: undefined, bizNo: undefined,
@ -214,7 +234,42 @@ const toggleFilters = () => {
} }
const productList = ref<ProductVO[]>([]) // const productList = ref<ProductVO[]>([]) //
const warehouseList = ref<WarehouseVO[]>([]) // const warehouseList = ref<WarehouseVO[]>([]) //
const categoryTabs = ref<ProductCategoryVO[]>([]) const categoryTabs = computed(() => getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE))
const isStockIn = (direction?: string) => direction === '入库'
const isStockOut = (direction?: string) => direction === '出库'
const getDirectionClass = (direction?: string) => {
if (isStockIn(direction)) return 'stock-record-in'
if (isStockOut(direction)) return 'stock-record-out'
return ''
}
const getDirectionTagType = (direction?: string) => {
if (isStockIn(direction)) return 'success'
if (isStockOut(direction)) return 'danger'
return 'info'
}
const formatNumber = (value: number | string | undefined) => {
if (value === undefined || value === null || value === '') return '-'
const num = Number(value)
return Number.isFinite(num) ? num.toLocaleString() : String(value)
}
const formatCountWithUnit = (row: StockRecordVO, withDirectionSign = false) => {
const value = withDirectionSign ? row.count : row.totalCount
const unit = row.unitName ? ` ${row.unitName}` : ''
if (value === undefined || value === null) return `-${unit}`
if (!withDirectionSign) return `${formatNumber(value)}${unit}`
const num = Number(value)
if (!Number.isFinite(num)) return `${value}${unit}`
const absValue = Math.abs(num).toLocaleString()
if (isStockIn(row.bizDirection)) return `+${absValue}${unit}`
if (isStockOut(row.bizDirection)) return `-${absValue}${unit}`
return `${formatNumber(value)}${unit}`
}
/** 查询列表 */ /** 查询列表 */
const getList = async () => { const getList = async () => {
@ -291,6 +346,7 @@ onActivated(() => {
}) })
onMounted(async () => { onMounted(async () => {
await dictStore.setDictMap()
await loadCategoryTabs() await loadCategoryTabs()
await getList() await getList()
// //
@ -301,22 +357,25 @@ onMounted(async () => {
/** tab 切换 */ /** tab 切换 */
const activeName = ref('') const activeName = ref('')
const handleTabClick = (tab: TabsPaneContext) => { const handleTabClick = (tab: TabsPaneContext) => {
queryParams.categoryId = tab.paneName ? Number(tab.paneName) : undefined queryParams.categoryType = tab.paneName ? Number(tab.paneName) : undefined
handleQuery() handleQuery()
} }
const loadCategoryTabs = async () => { const loadCategoryTabs = async () => {
try { const defaultValue = categoryTabs.value[0]?.value
const data = await ProductCategoryApi.getProductCategoryList({}) queryParams.categoryType = defaultValue !== undefined && defaultValue !== null ? Number(defaultValue) : undefined
const roots = (data || []).filter((item: any) => item && (item.parentId === 0 || item.parentId === null || item.parentId === undefined)) activeName.value = defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''
categoryTabs.value = roots.sort((a: any, b: any) => Number(a?.sort ?? 0) - Number(b?.sort ?? 0))
const defaultId = categoryTabs.value.find((v) => String(v.id) === '2')?.id ?? categoryTabs.value[0]?.id
queryParams.categoryId = defaultId
activeName.value = defaultId !== undefined && defaultId !== null ? String(defaultId) : ''
} catch {
categoryTabs.value = []
queryParams.categoryId = undefined
activeName.value = ''
}
} }
</script> </script>
<style scoped lang="scss">
.stock-record-in {
color: var(--el-color-success);
font-weight: 600;
}
.stock-record-out {
color: var(--el-color-danger);
font-weight: 600;
}
</style>

Loading…
Cancel
Save