|
|
|
|
@ -27,6 +27,22 @@
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item :label="t('ErpStock.Stock.category')" prop="categoryType">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="queryParams.categoryType"
|
|
|
|
|
clearable
|
|
|
|
|
:placeholder="t('ErpStock.Stock.placeholderCategory')"
|
|
|
|
|
class="!w-240px"
|
|
|
|
|
>
|
|
|
|
|
<el-option
|
|
|
|
|
v-for="item in categoryTypeOptions"
|
|
|
|
|
:key="item.value"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:value="item.value"
|
|
|
|
|
/>
|
|
|
|
|
</el-select>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item :label="t('ErpStock.Stock.warehouse')" prop="warehouseId">
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="queryParams.warehouseId"
|
|
|
|
|
@ -69,14 +85,6 @@
|
|
|
|
|
|
|
|
|
|
<!-- 列表 -->
|
|
|
|
|
<ContentWrap>
|
|
|
|
|
<el-tabs v-model="activeName" @tab-click="handleTabClick">
|
|
|
|
|
<el-tab-pane
|
|
|
|
|
v-for="item in categoryTabs"
|
|
|
|
|
:key="String(item.value)"
|
|
|
|
|
:label="item.label"
|
|
|
|
|
:name="String(item.value)"
|
|
|
|
|
/>
|
|
|
|
|
</el-tabs>
|
|
|
|
|
<el-table
|
|
|
|
|
v-loading="loading"
|
|
|
|
|
:data="list"
|
|
|
|
|
@ -92,9 +100,33 @@
|
|
|
|
|
{{ row.name || row.productName || '-' }}
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.category')" align="center" prop="categoryName" min-width="120" sortable />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.category')" align="center" prop="categoryType" min-width="120" sortable>
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<dict-tag :type="DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE" :value="row.categoryType" />
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.subCategory')" align="center" prop="categoryName" min-width="120" sortable />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.packagingRule')" align="center" prop="packagingRule" min-width="180" />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.warehouse')" align="center" prop="warehouseName" min-width="140" sortable />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.area')" align="center" prop="areaName" min-width="120" sortable />
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.stockDisplay')" align="center" prop="stockDisplay" min-width="220">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
<span
|
|
|
|
|
v-if="formatStockDisplay(row.stockDisplay).length"
|
|
|
|
|
class="stock-display"
|
|
|
|
|
:style="getStockDisplayStyle(row.categoryType)"
|
|
|
|
|
>
|
|
|
|
|
<span
|
|
|
|
|
v-for="item in formatStockDisplay(row.stockDisplay)"
|
|
|
|
|
:key="item"
|
|
|
|
|
class="stock-display__item"
|
|
|
|
|
>
|
|
|
|
|
{{ item }}
|
|
|
|
|
</span>
|
|
|
|
|
</span>
|
|
|
|
|
<span v-else>-</span>
|
|
|
|
|
</template>
|
|
|
|
|
</el-table-column>
|
|
|
|
|
<el-table-column :label="t('ErpStock.Stock.count')" align="center" sortable prop="count" min-width="120">
|
|
|
|
|
<template #default="{ row }">
|
|
|
|
|
{{ formatStockCount(row.count) }}
|
|
|
|
|
@ -124,12 +156,13 @@
|
|
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import download from '@/utils/download'
|
|
|
|
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
|
|
|
|
import { DICT_TYPE, getDictObj, getIntDictOptions } from '@/utils/dict'
|
|
|
|
|
import { StockApi, StockVO } from '@/api/erp/stock/stock'
|
|
|
|
|
import { ProductApi, ProductVO } from '@/api/erp/product/product'
|
|
|
|
|
import { WarehouseApi, WarehouseVO } from '@/api/erp/stock/warehouse'
|
|
|
|
|
import { useDictStoreWithOut } from '@/store/modules/dict'
|
|
|
|
|
import { formatDate } from '@/utils/formatTime'
|
|
|
|
|
import { isHexColor } from '@/utils/color'
|
|
|
|
|
/** ERP 产品库存列表 */
|
|
|
|
|
defineOptions({ name: 'ErpStock' })
|
|
|
|
|
|
|
|
|
|
@ -157,7 +190,7 @@ const queryFormRef = ref() // 搜索的表单
|
|
|
|
|
const exportLoading = ref(false) // 导出的加载中
|
|
|
|
|
const productList = ref<ProductVO[]>([]) // 产品列表
|
|
|
|
|
const warehouseList = ref<WarehouseVO[]>([]) // 仓库列表
|
|
|
|
|
const categoryTabs = computed(() => getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE))
|
|
|
|
|
const categoryTypeOptions = computed(() => getIntDictOptions(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE))
|
|
|
|
|
|
|
|
|
|
const formatStockCount = (value: number | string | undefined) => {
|
|
|
|
|
if (value === undefined || value === null || value === '') return '-'
|
|
|
|
|
@ -169,6 +202,25 @@ const formatStockTime = (value: any) => {
|
|
|
|
|
return value ? formatDate(value, 'YYYY-MM-DD HH:mm:ss') : '-'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const formatStockDisplay = (value: string | undefined) => {
|
|
|
|
|
if (!value) return []
|
|
|
|
|
return value
|
|
|
|
|
.split(',')
|
|
|
|
|
.map((item) => item.trim())
|
|
|
|
|
.filter(Boolean)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getStockDisplayStyle = (categoryType: number | string | undefined) => {
|
|
|
|
|
const dict = getDictObj(DICT_TYPE.MATERIAL_CLASSIFICATION_TYPE, categoryType)
|
|
|
|
|
if (dict?.cssClass && isHexColor(dict.cssClass)) {
|
|
|
|
|
return { color: dict.cssClass }
|
|
|
|
|
}
|
|
|
|
|
const colorType = dict?.colorType && !['primary', 'default'].includes(String(dict.colorType))
|
|
|
|
|
? dict.colorType
|
|
|
|
|
: 'primary'
|
|
|
|
|
return { color: `var(--el-color-${colorType})` }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const getLatestInTime = (row: any) => {
|
|
|
|
|
return row.latestInTime ?? row.lastInTime ?? row.recentInTime ?? row.latestStockInTime ?? row.lastStockInTime
|
|
|
|
|
}
|
|
|
|
|
@ -177,11 +229,17 @@ const getLatestOutTime = (row: any) => {
|
|
|
|
|
return row.latestOutTime ?? row.lastOutTime ?? row.recentOutTime ?? row.latestStockOutTime ?? row.lastStockOutTime
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const buildQueryParams = () => {
|
|
|
|
|
return Object.fromEntries(
|
|
|
|
|
Object.entries(queryParams).filter(([, value]) => value !== undefined && value !== null && value !== '')
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 查询列表 */
|
|
|
|
|
const getList = async () => {
|
|
|
|
|
loading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const data = await StockApi.getStockPage(queryParams)
|
|
|
|
|
const data = await StockApi.getStockPage(buildQueryParams())
|
|
|
|
|
list.value = data.list
|
|
|
|
|
total.value = data.total
|
|
|
|
|
} finally {
|
|
|
|
|
@ -229,7 +287,7 @@ const handleExport = async () => {
|
|
|
|
|
exportLoading.value = true
|
|
|
|
|
const ids = selectionList.value.map((item) => item.id).filter((v) => v != null)
|
|
|
|
|
const params = {
|
|
|
|
|
...queryParams,
|
|
|
|
|
...buildQueryParams(),
|
|
|
|
|
ids: ids.length ? ids.join(',') : undefined
|
|
|
|
|
}
|
|
|
|
|
const data = await StockApi.exportStock(params)
|
|
|
|
|
@ -249,23 +307,24 @@ const handleSelectionChange = (rows: StockVO[]) => {
|
|
|
|
|
/** 初始化 **/
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
await dictStore.setDictMap()
|
|
|
|
|
await loadCategoryTabs()
|
|
|
|
|
await getList()
|
|
|
|
|
// 加载产品、仓库列表
|
|
|
|
|
productList.value = await ProductApi.getProductSimpleList()
|
|
|
|
|
warehouseList.value = await WarehouseApi.getWarehouseSimpleList()
|
|
|
|
|
})
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
/** tab 切换 */
|
|
|
|
|
const activeName = ref('')
|
|
|
|
|
const handleTabClick = (tab: TabsPaneContext) => {
|
|
|
|
|
queryParams.categoryType = tab.paneName ? Number(tab.paneName) : undefined
|
|
|
|
|
handleQuery()
|
|
|
|
|
<style scoped>
|
|
|
|
|
.stock-display {
|
|
|
|
|
display: inline-flex;
|
|
|
|
|
align-items: center;
|
|
|
|
|
justify-content: center;
|
|
|
|
|
gap: 18px;
|
|
|
|
|
color: var(--el-color-primary);
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loadCategoryTabs = async () => {
|
|
|
|
|
const defaultValue = categoryTabs.value[0]?.value
|
|
|
|
|
queryParams.categoryType = defaultValue !== undefined && defaultValue !== null ? Number(defaultValue) : undefined
|
|
|
|
|
activeName.value = defaultValue !== undefined && defaultValue !== null ? String(defaultValue) : ''
|
|
|
|
|
.stock-display__item {
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
}
|
|
|
|
|
</script>
|
|
|
|
|
</style>
|
|
|
|
|
|