|
|
|
|
@ -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>
|
|
|
|
|
|