查看操作历史

This commit is contained in:
2025-11-27 18:35:03 +08:00
parent 1ddd3f8c90
commit 01db083b8e
2 changed files with 170 additions and 7 deletions

View File

@@ -1,6 +1,58 @@
<template>
<div>
<el-table :data="stockList" style="width: 100%" v-loading="loading">
<el-table
:data="stockList"
style="width: 100%"
v-loading="loading"
row-key="raw_material_id"
@expand-change="handleExpandChange"
@row-click="handleRowClick"
>
<el-table-column type="expand">
<template #default="props">
<div style="padding: 10px 20px;">
<h4 style="margin-bottom: 16px;">历史操作记录 ({{ props.row.raw_material_name }})</h4>
<el-table :data="props.row.stock_logs" border v-loading="props.row.stock_log_loading">
<el-table-column prop="happened_at" label="操作时间" width="180">
<template #default="scope">
{{ formatRFC3339(scope.row.happened_at) }}
</template>
</el-table-column>
<el-table-column prop="source_type" label="操作类型" width="120">
<template #default="scope">
{{ getStockLogSourceTypeLabel(scope.row.source_type) }}
</template>
</el-table-column>
<el-table-column prop="change_amount" label="变动数量" width="120">
<template #default="scope">
{{ formatChangeAmount(scope.row.change_amount) }}
</template>
</el-table-column>
<el-table-column prop="before_quantity" label="变动前库存" width="120">
<template #default="scope">
{{ formatWeight(scope.row.before_quantity) }}
</template>
</el-table-column>
<el-table-column prop="after_quantity" label="变动后库存" width="120">
<template #default="scope">
{{ formatWeight(scope.row.after_quantity) }}
</template>
</el-table-column>
<el-table-column prop="remarks" label="备注"></el-table-column>
</el-table>
<el-pagination
v-if="props.row.stock_log_pagination && props.row.stock_log_pagination.total > 0"
style="margin-top: 20px;"
:current-page="props.row.stock_log_pagination.page"
:page-size="props.row.stock_log_pagination.page_size"
:total="props.row.stock_log_pagination.total"
layout="total, sizes, prev, pager, next, jumper"
@size-change="(size) => handleStockLogSizeChange(props.row, size)"
@current-change="(page) => handleStockLogCurrentChange(props.row, page)"
></el-pagination>
</div>
</template>
</el-table-column>
<el-table-column prop="raw_material_name" label="原料名称"></el-table-column>
<el-table-column prop="stock" label="当前库存">
<template #default="scope">
@@ -36,10 +88,10 @@
</template>
<script>
import { ref, onMounted, watch } from 'vue';
import { ref, onMounted, watch, nextTick } from 'vue';
import { InventoryApi } from '../../api/inventory';
import { ElMessage } from 'element-plus';
import { formatRFC3339, formatWeight } from '../../utils/format';
import { formatRFC3339, formatWeight, formatChangeAmount } from '../../utils/format'; // 导入 formatChangeAmount
import { getStockLogSourceTypeLabel } from '../../enums'; // 导入 getStockLogSourceTypeLabel
export default {
@@ -64,6 +116,9 @@ export default {
total: 0,
});
// el-table 的引用,用于控制行的展开/折叠
const mainTable = ref(null);
const fetchStockList = async (filter = props.stockFilter, rawMaterialName = props.searchRawMaterialName) => {
loading.value = true;
try {
@@ -78,7 +133,17 @@ export default {
params.raw_material_name = rawMaterialName;
}
const res = await InventoryApi.getCurrentStockList(params);
stockList.value = res.data.list;
// 初始化 stock_logs 和 stock_log_pagination
stockList.value = res.data.list.map(item => ({
...item,
stock_logs: [], // 存储历史操作记录
stock_log_loading: false, // 历史操作记录的加载状态
stock_log_pagination: { // 历史操作记录的分页信息
page: 1,
page_size: 10,
total: 0,
},
}));
pagination.value.total = res.data.pagination.total;
} catch (error) {
ElMessage.error('获取库存列表失败');
@@ -102,6 +167,78 @@ export default {
emit('adjust-stock', row); // 只传递行数据
};
/**
* 处理行展开/折叠事件
* @param {object} row - 当前行数据
* @param {Array<object>} expandedRows - 所有已展开的行数据
*/
const handleExpandChange = async (row, expandedRows) => {
const isExpanded = expandedRows.some(r => r.raw_material_id === row.raw_material_id);
// 仅在展开时且数据未加载时才请求
if (isExpanded) {
// 确保每次展开都重新加载第一页数据,或者根据当前分页状态加载
// 如果是第一次展开,或者用户手动切换了分页,则需要重新获取
await fetchStockLogs(row);
}
};
/**
* 获取指定原料的历史操作记录
* @param {object} row - 当前原料行数据
*/
const fetchStockLogs = async (row) => {
row.stock_log_loading = true;
try {
const params = {
raw_material_id: row.raw_material_id,
page: row.stock_log_pagination.page,
page_size: row.stock_log_pagination.page_size,
order_by: 'happened_at DESC', // 按时间倒序
};
const res = await InventoryApi.getStockLogList(params);
if (res.data) {
row.stock_logs = res.data.list;
row.stock_log_pagination.total = res.data.pagination.total;
}
} catch (error) {
console.error('获取库存历史操作记录失败:', error);
ElMessage.error('获取库存历史操作记录失败');
} finally {
row.stock_log_loading = false;
}
};
/**
* 处理历史操作记录分页的每页大小变化
* @param {object} row - 当前原料行数据
* @param {number} size - 新的每页大小
*/
const handleStockLogSizeChange = async (row, size) => {
row.stock_log_pagination.page_size = size;
row.stock_log_pagination.page = 1; // 重置页码到第一页
await fetchStockLogs(row);
};
/**
* 处理历史操作记录分页的当前页码变化
* @param {object} row - 当前原料行数据
* @param {number} page - 新的页码
*/
const handleStockLogCurrentChange = async (row, page) => {
row.stock_log_pagination.page = page;
await fetchStockLogs(row);
};
// 处理行点击事件,用于切换行的展开状态
const handleRowClick = (row, column) => {
// 如果点击的是操作列,则不执行任何操作
if (column && column.label === '操作') {
return;
}
// 否则,切换行的展开状态
mainTable.value.toggleRowExpansion(row);
};
onMounted(() => {
fetchStockList();
});
@@ -125,13 +262,19 @@ export default {
stockList,
loading,
pagination,
mainTable, // 暴露 mainTable ref
handleSizeChange,
handleCurrentChange,
formatRFC3339,
formatWeight,
formatChangeAmount, // 暴露 formatChangeAmount
handleAdjust,
getStockLogSourceTypeLabel, // 暴露辅助函数给模板
getStockLogSourceTypeLabel,
handleExpandChange,
handleStockLogSizeChange,
handleStockLogCurrentChange,
handleRowClick,
};
},
};
</script>
</script>

View File

@@ -34,5 +34,25 @@ export function formatWeight(grams) {
}
}
/**
* 格式化库存变动数量,显示正负号和单位 (kg 或 g)
* @param {number} changeAmount - 变动数量,单位为克 (正数入库,负数出库)
* @returns {string} - 格式化后的变动数量字符串 (例如 "+1.5 kg", "-500 g")
*/
export function formatChangeAmount(changeAmount) {
if (typeof changeAmount !== 'number' || isNaN(changeAmount)) {
return '--';
}
const sign = changeAmount > 0 ? '+' : '';
const absoluteAmount = Math.abs(changeAmount);
if (absoluteAmount >= 1000) {
return sign + (absoluteAmount / 1000).toFixed(2) + ' kg';
} else {
return sign + absoluteAmount + ' g';
}
}
// 你未来还可以添加其他全局格式化函数
// export function formatCurrency(number) { ... }
// export function formatCurrency(number) { ... }