+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ formatDecimal(scope.row.currentStock) }}
+
+
+
+
+ {{ formatDecimal(scope.row.inTransitNum) }}
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
+// 响应式数据:接口返回列表
+const materialList = ref([]) // 材料列表
+const purchaseInDetailList = ref([]) // 入库列表
+const materialOutList = ref([]) // 出库列表
+// 加载状态
+const loading = ref(false)
+// 分页参数(若依接口标准分页)
+const queryParams = reactive({
+ pageNum: 1,
+ pageSize: 10
+})
+const total = ref(0) // 材料总条数
+
+// 格式化数值:保留2位小数,处理字符串转数字
+const formatNumber = (row, column) => {
+ return Number(row[column.prop] || 0).toFixed(2)
+}
+
+// 分页后的材料列表(计算属性)
+const paginationMaterialList = computed(() => {
+ const start = (queryParams.pageNum - 1) * queryParams.pageSize
+ const end = start + queryParams.pageSize
+ return materialList.value.slice(start, end)
+})
+
+// 指标卡数据:库存总量、材料类型数、库存操作数、库存变化量
+const statCards = ref([
+ { title: '库存总量', value: 0, suffix: '件', precision: 0, key: 'totalStock' },
+ { title: '材料类型数量', value: 0, key: 'materialTypeCount', precision: 0 },
+ { title: '库存操作数', value: 0, key: 'stockOperateCount', precision: 0 },
+ { title: '库存变化量', value: 0, suffix: '件', precision: 0, key: 'stockChange' }
+])
+
+// 图表数据源(供子组件使用)
+const factoryBarData = ref([]) // 厂家汇总柱状图数据
+const stockTrendData = ref([]) // 库存趋势折线图数据
+const inOutCompareData = ref([]) // 出入库对比折线图数据
+
+// 1. 获取材料列表(带分页)
+const getMaterialList = async () => {
+ try {
+ const res = await listMaterial(queryParams) // 传入分页参数
+ materialList.value = res.rows || []
+ total.value = res.total || 0 // 若依接口返回total总条数
+ } catch (err) {
+ console.error('获取材料列表失败:', err)
+ materialList.value = []
+ }
+}
+
+// 2. 获取入库+出库列表(无需分页,取全部数据做统计)
+const getInOutList = async () => {
+ try {
+ // 并行请求,提高效率
+ const [inRes, outRes] = await Promise.all([
+ listPurchaseInDetail(),
+ listMaterialOut()
+ ])
+ purchaseInDetailList.value = inRes.rows || []
+ materialOutList.value = outRes.rows || []
+ } catch (err) {
+ console.error('获取出入库列表失败:', err)
+ purchaseInDetailList.value = []
+ materialOutList.value = []
+ }
+}
+
+// 3. 计算指标卡数值
+const calcStatCards = () => {
+ // 库存总量:所有材料当前库存求和
+ const totalStock = materialList.value.reduce((sum, item) => {
+ return sum + Number(item.currentStock || 0)
+ }, 0)
+ // 材料类型数量:去重(按materialId)
+ const materialTypeCount = new Set(materialList.value.map(item => item.materialId)).size
+ // 库存操作数:入库次数+出库次数
+ const stockOperateCount = purchaseInDetailList.value.length + materialOutList.value.length
+ // 库存变化量:总入库数 - 总出库数
+ const totalInNum = purchaseInDetailList.value.reduce((sum, item) => sum + Number(item.inNum || 0), 0)
+ const totalOutNum = materialOutList.value.reduce((sum, item) => sum + Number(item.outNum || 0), 0)
+ const stockChange = totalInNum - totalOutNum
+
+ // 更新指标卡
+ statCards.value = [
+ { title: '库存总量', value: totalStock, suffix: '件', precision: 2, key: 'totalStock' },
+ { title: '材料类型数量', value: materialTypeCount, key: 'materialTypeCount', precision: 0 },
+ { title: '库存操作数', value: stockOperateCount, key: 'stockOperateCount', precision: 0 },
+ { title: '库存变化量', value: stockChange, suffix: '件', precision: 2, key: 'stockChange' }
+ ]
+}
+
+// 4. 转换厂家汇总柱状图数据:按厂家分组,统计材料数+库存数
+const transformFactoryBarData = () => {
+ const factoryMap = new Map()
+ // 按厂家分组
+ materialList.value.forEach(item => {
+ const factory = item.factory || '未知厂家'
+ if (!factoryMap.has(factory)) {
+ factoryMap.set(factory, {
+ materialCount: 0, // 材料个数(去重后)
+ stockTotal: 0, // 库存总数
+ materialIds: new Set() // 去重材料ID
+ })
+ }
+ const factoryItem = factoryMap.get(factory)
+ factoryItem.materialIds.add(item.materialId)
+ factoryItem.materialCount = factoryItem.materialIds.size
+ factoryItem.stockTotal += Number(item.currentStock || 0)
+ })
+ // 转换为数组供图表使用
+ factoryBarData.value = Array.from(factoryMap).map(([factory, data]) => ({
+ factory,
+ materialCount: data.materialCount,
+ stockTotal: data.stockTotal.toFixed(2)
+ }))
+}
+
+// 5. 转换库存趋势+出入库对比图表数据(按时间分组)
+const transformTimeTrendData = () => {
+ // 整合所有时间操作记录:入库+出库,统一格式
+ const allOperate = [
+ ...purchaseInDetailList.value.map(item => ({
+ time: dayjs(item.inTime).format('YYYY-MM-DD'),
+ type: 'in',
+ num: Number(item.inNum || 0)
+ })),
+ ...materialOutList.value.map(item => ({
+ time: dayjs(item.outTime).format('YYYY-MM-DD'),
+ type: 'out',
+ num: Number(item.outNum || 0)
+ }))
+ ]
+ if (allOperate.length === 0) {
+ stockTrendData.value = []
+ inOutCompareData.value = []
+ return
+ }
+
+ // 按时间排序,获取所有唯一时间(升序)
+ const timeSet = new Set(allOperate.map(item => item.time))
+ const timeList = Array.from(timeSet).sort((a, b) => dayjs(a) - dayjs(b))
+
+ // 初始化时间分组数据:统计每日入库/出库数
+ const timeDataMap = {}
+ timeList.forEach(time => {
+ timeDataMap[time] = { in: 0, out: 0 }
+ })
+ allOperate.forEach(item => {
+ timeDataMap[item.time][item.type] += item.num
+ })
+
+ // 转换出入库对比数据
+ inOutCompareData.value = timeList.map(time => ({
+ time,
+ inNum: timeDataMap[time].in,
+ outNum: timeDataMap[time].out
+ }))
+
+ // 转换库存趋势数据:累计库存 = 初始库存 + 累计入库 - 累计出库
+ // 初始库存:当前总库存 - (总入库 - 总出库),保证趋势图最后一个点匹配当前库存
+ const totalStockNow = materialList.value.reduce((sum, item) => sum + Number(item.currentStock || 0), 0)
+ const totalInAll = purchaseInDetailList.value.reduce((sum, item) => sum + Number(item.inNum || 0), 0)
+ const totalOutAll = materialOutList.value.reduce((sum, item) => sum + Number(item.outNum || 0), 0)
+ const initStock = totalStockNow - (totalInAll - totalOutAll)
+
+ let cumulativeIn = 0 // 累计入库
+ let cumulativeOut = 0 // 累计出库
+ stockTrendData.value = timeList.map(time => {
+ cumulativeIn += timeDataMap[time].in
+ cumulativeOut += timeDataMap[time].out
+ const currentStock = initStock + cumulativeIn - cumulativeOut
+ return {
+ time,
+ stock: currentStock < 0 ? 0 : currentStock // 库存不能为负
+ }
+ })
+}
+
+// 核心:加载所有数据并处理转换
+const loadAllData = async () => {
+ loading.value = true
+ try {
+ // 并行请求所有数据
+ await Promise.all([
+ getMaterialList(),
+ getInOutList()
+ ])
+ // 数据转换:指标卡 + 所有图表
+ calcStatCards()
+ transformFactoryBarData()
+ transformTimeTrendData()
+ } catch (err) {
+ console.error('数据加载失败:', err)
+ } finally {
+ loading.value = false
+ }
+}
+
+// 页面挂载时加载数据
+onMounted(() => {
+ loadAllData()
+})
+
+
+
\ No newline at end of file
diff --git a/gear-ui3/src/views/mat/in/index.vue b/gear-ui3/src/views/mat/in/index.vue
index 479bf2e..858df45 100644
--- a/gear-ui3/src/views/mat/in/index.vue
+++ b/gear-ui3/src/views/mat/in/index.vue
@@ -2,7 +2,7 @@