You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

453 lines
12 KiB
Vue

<template>
<div class="inventory-table-container">
<div class="table-header">
<h3>实时库存表</h3>
<div class="table-actions">
<el-switch
v-model="showDifference"
active-text="显示库存变化"
inactive-text="显示实际库存"
style="margin-right: 15px;"
@change="handleToggleChange"
/>
<el-button @click="refreshData" type="primary" size="small">刷新数据</el-button>
</div>
</div>
<!-- 调试信息 -->
<div v-if="!loading" style="margin-bottom: 10px; font-size: 12px; color: #666;">
调试信息: 获取到 {{ records.length }} 条记录表格共 {{ tableData.length }}
</div>
<div v-loading="loading" class="table-wrapper">
<el-table
:data="tableData"
style="width: 100%; min-width: max-content;"
border
:header-cell-style="{ backgroundColor: '#f5f7fa', color: '#606266' }"
empty-text="暂无数据"
:scrollbar-always-on="true"
@cell-dblclick="handleCellDblClick"
>
<!-- 规格列 -->
<el-table-column
prop="specification"
label="规格"
width="80"
fixed="left"
/>
<!-- 动态列model-wire_disc 组合 -->
<el-table-column
v-for="column in dynamicColumns"
:key="column.key"
:label="column.label"
:prop="column.prop"
min-width="120"
>
<template #default="scope">
<div class="cell-content">
<span v-if="!showDifference">
{{ scope.row[column.prop] || '-' }}
</span>
<span v-else>
{{ scope.row[column.prop] || '-' }}
<span
v-if="scope.row[column.prop + '_difference'] !== undefined && scope.row[column.prop + '_difference'] !== null"
:class="getDifferenceClass(scope.row[column.prop + '_difference'])"
style="margin-left: 5px; font-size: 12px;"
>
({{ formatDifference(scope.row[column.prop + '_difference']) }})
</span>
<span v-else class="no-data" style="margin-left: 5px; font-size: 12px;">
(-)
</span>
</span>
</div>
</template>
<template #header>
<div v-html="column.label"></div> <!-- 使 v-html HTML <br> 生效 -->
</template>
</el-table-column>
<!-- 总计列 -->
<el-table-column
label="总计"
width="100"
fixed="right"
>
<template #default="scope">
{{ scope.row.total }}
</template>
</el-table-column>
</el-table>
</div>
<!-- WmsTable 详情对话框 -->
<el-dialog
v-model="wmsDialogVisible"
title="库存详情"
width="80%"
destroy-on-close
>
<WmsTable
v-if="wmsDialogVisible"
ref="wmsTableRef"
:model="currentWmsModel"
:specification="currentWmsSpecification"
:loading-height="200"
:show-action="true"
/>
</el-dialog>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { API_CONFIG } from "@/config/api"
import { ElMessage } from 'element-plus'
import WmsTable from '@/components/WmsTable/index.vue'
// 响应式数据
const loading = ref(false)
const records = ref([])
const differenceRecords = ref([])
// WMS对话框相关状态
const wmsDialogVisible = ref(false)
const currentWmsModel = ref('')
const currentWmsSpecification = ref('')
const wmsTableRef = ref(null)
// 显示控制
const showDifference = ref(true)
// 计算属性:动态列
const dynamicColumns = computed(() => {
if (!records.value.length) return [];
// 使用 '::' 作为分隔符
const combinations = [...new Set(records.value.map(item => {
if (item.wire_disc && item.wire_disc.trim() !== '') {
return `${item.model}::${item.wire_disc}`;
} else {
return item.model;
}
}))].sort(); // 可选:若需自定义排序,调整这里
return combinations.map(comb => {
// 将组合拆分为 model 和 wire_disc
const hasWireDisc = comb.includes('::');
const [model, wire_disc] = hasWireDisc ? comb.split('::') : [comb, ''];
return {
key: comb,
prop: comb,
label: `${model}<br>${wire_disc}` // 使用HTML换行符实现两行显示
};
});
});
// 计算属性:表格数据
const tableData = computed(() => {
console.log('计算表格数据, records.value:', records.value);
if (!records.value.length) {
console.log('records为空返回空数组');
return [];
}
// 获取所有唯一的规格并从小到大排序(可选数值排序)
const specifications = [...new Set(records.value.map(item => item.specification))]
.sort((a, b) => parseFloat(a) - parseFloat(b)); // 改为数值排序,避免 "0.800" 在前
console.log('获取到的规格列表:', specifications);
// 获取所有唯一的 model::wire_disc 组合
const combinations = [...new Set(records.value.map(item => {
if (item.wire_disc && item.wire_disc.trim() !== '') {
return `${item.model}::${item.wire_disc}`;
} else {
return item.model;
}
}))];
console.log('获取到的model::wire_disc组合:', combinations);
// 构建表格数据
const tableDataResult = specifications.map(specification => {
const row = { specification };
let total = 0;
combinations.forEach(comb => {
// 判断是否包含 wire_disc检查 '::'
const hasWireDisc = comb.includes('::');
let model, wire_disc;
if (hasWireDisc) {
[model, wire_disc] = comb.split('::'); // 使用 '::' 分割
} else {
model = comb;
wire_disc = null;
}
// 查找对应的记录
const record = records.value.find(r => {
const specMatch = r.specification === specification;
const modelMatch = r.model === model;
const wireDiscMatch = hasWireDisc
? (r.wire_disc === wire_disc)
: (!r.wire_disc || r.wire_disc.trim() === '');
return specMatch && modelMatch && wireDiscMatch;
});
// 设置实际库存数量
row[comb] = record ? record.total_number : null;
if (record) total += record.total_number;
// 如果启用了差值显示,查找差值记录
if (showDifference.value && differenceRecords.value.length > 0) {
const differenceRecord = differenceRecords.value.find(r => {
const specMatch = r.specification === specification;
const modelMatch = r.model === model;
const wireDiscMatch = hasWireDisc
? (r.wire_disc === wire_disc)
: (!r.wire_disc || r.wire_disc.trim() === '');
return specMatch && modelMatch && wireDiscMatch;
});
// 设置差值
row[comb + '_difference'] = differenceRecord ? differenceRecord.difference : null;
}
});
row.total = total;
return row;
});
console.log('生成的表格数据:', tableDataResult);
return tableDataResult;
});
// 方法:获取数据
const fetchData = async () => {
loading.value = true;
try {
console.log('正在请求API:', `${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.WMS_TYPE_1_RECORDS}`);
const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.WMS_TYPE_1_RECORDS}`);
const result = await response.json();
console.log('API返回结果:', result);
if (result.code === 200 && result.data && result.data.records) {
records.value = result.data.records;
console.log('设置records值:', records.value);
} else {
console.error('获取实时库存数据失败:', result.message);
}
} catch (error) {
console.error('API调用失败:', error);
} finally {
loading.value = false;
}
};
// 方法:获取差值数据
const fetchDifferenceData = async () => {
const today = new Date().toISOString().split('T')[0]; // 获取今天的日期 YYYY-MM-DD
const targetDate = today;
try {
console.log('正在请求差值API:', `/api/wms/difference/type1-records?target_date=${targetDate}`);
const response = await fetch(`${API_CONFIG.BASE_URL}/api/wms/difference/type1-records?target_date=${targetDate}`);
const result = await response.json();
console.log('差值API返回结果:', result);
if (result.code === 200 && result.data && result.data.records) {
differenceRecords.value = result.data.records;
console.log('设置差值records:', differenceRecords.value);
} else {
console.error('获取差值数据失败:', result.message);
differenceRecords.value = [];
}
} catch (error) {
console.error('差值API调用失败:', error);
differenceRecords.value = [];
}
};
// 方法:刷新数据
const refreshData = () => {
fetchData();
if (showDifference.value) {
fetchDifferenceData();
}
};
// 方法处理toggle变化
const handleToggleChange = (value) => {
if (value) {
// 启用差值显示时获取差值数据
fetchDifferenceData();
} else {
// 禁用差值显示时清空差值数据
differenceRecords.value = [];
}
};
// 方法:格式化差值显示
const formatDifference = (difference) => {
if (difference === 0) return '0';
if (difference > 0) return `+${difference}`;
return `${difference}`;
};
// 方法:获取差值样式类
const getDifferenceClass = (difference) => {
if (difference > 0) return 'difference-positive'; // 绿色,增加
if (difference < 0) return 'difference-negative'; // 红色,减少
return 'difference-zero'; // 黑色,无变化
};
// 方法:处理单元格双击事件
const handleCellDblClick = (row, column, cell, event) => {
const cellValue = row[column.property];
// 检查单元格是否有值
if (!cellValue || cellValue === '-' || cellValue === null || cellValue === undefined) {
ElMessage.warning('该单元格暂无数据');
return;
}
// 检查是否是规格列或总计列这些列不需要显示WMS详情
if (column.property === 'specification' || column.property === 'total') {
ElMessage.info('该列不支持查看详情');
return;
}
// 从列属性中提取model和wire_disc
const columnKey = column.property;
const hasWireDisc = columnKey.includes('::');
let model, wire_disc;
if (hasWireDisc) {
[model, wire_disc] = columnKey.split('::');
} else {
model = columnKey;
wire_disc = null;
}
// 设置当前WMS数据的参数
currentWmsModel.value = model;
currentWmsSpecification.value = row.specification;
// 显示WMS详情对话框
wmsDialogVisible.value = true;
};
// 组件挂载时获取数据
onMounted(() => {
fetchData();
// 如果默认显示库存变化,则同时获取差值数据
if (showDifference.value) {
fetchDifferenceData();
}
});
</script>
<style scoped>
.inventory-table-container {
padding: 20px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.table-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.table-header h3 {
margin: 0;
font-size: 18px;
color: #303133;
}
.table-actions {
display: flex;
gap: 10px;
}
.table-wrapper {
width: 100%;
overflow-x: auto;
/* 确保滚动条始终可见 */
scrollbar-width: thin; /* Firefox */
}
:deep(.el-table) {
font-size: 14px;
/* 确保表格最小宽度正确计算 */
width: max-content !important;
min-width: 100% !important;
}
:deep(.el-table th) {
background-color: #f5f7fa !important;
color: #606266;
font-weight: 600;
white-space: nowrap;
text-align: center; /* 可选:居中对齐列头 */
padding: 8px 0; /* 调整列头内间距,以适应两行显示 */
}
:deep(.el-table td) {
padding: 8px 0;
white-space: nowrap;
}
/* 库存变化样式 */
.cell-content {
text-align: center;
}
.difference-positive {
color: #67c23a;
font-weight: bold;
}
.difference-negative {
color: #f56c6c;
font-weight: bold;
}
.difference-zero {
color: #606266;
font-weight: normal;
}
.no-data {
color: #c0c4cc;
}
/* Webkit 浏览器的滚动条样式 */
.table-wrapper::-webkit-scrollbar {
height: 10px;
}
.table-wrapper::-webkit-scrollbar-track {
background: #f1f1f1;
}
.table-wrapper::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 5px;
}
.table-wrapper::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
</style>