feat:出入库明细模块

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

@ -2,15 +2,28 @@ import request from '@/config/axios'
// ERP 产品库存明细 VO
export interface StockRecordVO {
id: number // 编号
productId: number // 产品编号
warehouseId: number // 仓库编号
count: number // 出入库数量
totalCount: number // 总库存量
bizType: number // 业务类型
bizId: number // 业务编号
bizItemId: number // 业务项编号
bizNo: string // 业务单号
id: number
productId: number
bizDirection?: string
bizDocType?: number
categoryType?: number
warehouseId: number
areaId?: number
areaName?: 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

@ -111,7 +111,12 @@
<!-- 列表 -->
<ContentWrap>
<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-table
@ -123,48 +128,54 @@
@selection-change="handleSelectionChange"
>
<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.categoryName')" align="center" prop="categoryName" 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>
<el-table-column :label="t('ErpStock.Record.id')" align="center" prop="id" width="100" sortable />
<el-table-column :label="t('ErpStock.Record.bizDirection')" align="center" prop="bizDirection" min-width="90" sortable>
<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>
</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
:label="t('ErpStock.Record.count')"
align="right"
align="center"
sortable
prop="count"
width="120px"
:formatter="erpCountTableColumnFormatter"
/>
min-width="120"
>
<template #default="scope">
<span :class="getDirectionClass(scope.row.bizDirection)">
{{ formatCountWithUnit(scope.row, true) }}
</span>
</template>
</el-table-column>
<el-table-column
:label="t('ErpStock.Record.totalCount')"
align="right"
align="center"
sortable
prop="totalCount"
width="120px"
:formatter="erpCountTableColumnFormatter"
/>
min-width="120"
>
<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
:label="t('ErpStock.Record.recordTime')"
align="center"
sortable
prop="recordTime"
:formatter="dateFormatter2"
width="120px"
/>
<el-table-column
:label="t('ErpStock.Record.createTime')"
align="center"
prop="createTime"
:formatter="dateFormatter"
width="180px"
sortable />
<el-table-column :label="t('ErpStock.Record.creatorName')" align="center" prop="creatorName" sortable />
/>
</el-table>
<!-- 分页 -->
<Pagination
@ -178,28 +189,37 @@
<script setup lang="ts">
import { getIntDictOptions, DICT_TYPE } from '@/utils/dict'
import {dateFormatter, dateFormatter2} from '@/utils/formatTime'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { StockRecordApi, StockRecordVO } from '@/api/erp/stock/record'
import { ProductApi, ProductVO } from '@/api/erp/product/product'
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
import { ProductCategoryApi, ProductCategoryVO } from '@/api/erp/product/category'
import { erpCountTableColumnFormatter } from '@/utils'
import { useDictStoreWithOut } from '@/store/modules/dict'
/** ERP 产品库存明细列表 */
defineOptions({ name: 'ErpStockRecord' })
const message = useMessage() //
const { t } = useI18n() //
const dictStore = useDictStoreWithOut()
const loading = ref(true) //
const list = ref<StockRecordVO[]>([]) //
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,
pageSize: 10,
productId: undefined,
categoryId: undefined,
categoryType: undefined,
warehouseId: undefined,
bizType: undefined,
bizNo: undefined,
@ -214,7 +234,42 @@ const toggleFilters = () => {
}
const productList = ref<ProductVO[]>([]) //
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 () => {
@ -291,6 +346,7 @@ onActivated(() => {
})
onMounted(async () => {
await dictStore.setDictMap()
await loadCategoryTabs()
await getList()
//
@ -301,22 +357,25 @@ onMounted(async () => {
/** tab 切换 */
const activeName = ref('')
const handleTabClick = (tab: TabsPaneContext) => {
queryParams.categoryId = tab.paneName ? Number(tab.paneName) : undefined
queryParams.categoryType = tab.paneName ? Number(tab.paneName) : undefined
handleQuery()
}
const loadCategoryTabs = async () => {
try {
const data = await ProductCategoryApi.getProductCategoryList({})
const roots = (data || []).filter((item: any) => item && (item.parentId === 0 || item.parentId === null || item.parentId === undefined))
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 = ''
}
const defaultValue = categoryTabs.value[0]?.value
queryParams.categoryType = defaultValue !== undefined && defaultValue !== null ? Number(defaultValue) : undefined
activeName.value = defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''
}
</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