feat(wms): 新增报表透视表组件并优化操作状态显示
refactor: 替换select为tag显示操作状态 feat: 添加今天按钮到时间范围选择器 fix: 移除调试用的console.log style: 调整按钮间距样式 feat: 新增厂家材质透视表和宽度厚度统计表 refactor: 优化导出功能去除orderBy参数 feat: 添加表面处理等查询条件 feat: 在coilTable中添加settings插槽 feat: 使用下拉菜单整合报表操作按钮
This commit is contained in:
@@ -191,13 +191,17 @@
|
||||
|
||||
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态"
|
||||
<!-- <el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态"
|
||||
@change="handleStatusChange(scope.row)">
|
||||
<el-option label="待处理" :value="0" />
|
||||
<el-option label="处理中" :value="1" />
|
||||
<el-option label="已完成" :value="2" />
|
||||
<el-option label="已取消" :value="3" />
|
||||
</el-select>
|
||||
</el-select> -->
|
||||
<el-tag v-if="scope.row.actionStatus === 0" type="info" size="mini">待处理</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 1" type="warning" size="mini">处理中</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 2" type="success" size="mini">已完成</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 3" type="danger" size="mini">已取消</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
@@ -72,12 +72,16 @@
|
||||
|
||||
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
|
||||
<template slot-scope="scope">
|
||||
<el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态" @change="handleStatusChange(scope.row)">
|
||||
<!-- <el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态" @change="handleStatusChange(scope.row)">
|
||||
<el-option label="待处理" :value="0" />
|
||||
<el-option label="处理中" :value="1" />
|
||||
<el-option label="已完成" :value="2" />
|
||||
<el-option label="已取消" :value="3" />
|
||||
</el-select>
|
||||
</el-select> -->
|
||||
<el-tag v-if="scope.row.actionStatus === 0" type="info" size="mini">待处理</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 1" type="warning" size="mini">处理中</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 2" type="success" size="mini">已完成</el-tag>
|
||||
<el-tag v-else-if="scope.row.actionStatus === 3" type="danger" size="mini">已取消</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
|
||||
@@ -51,6 +51,27 @@
|
||||
clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="表面处理">
|
||||
<el-input v-model="queryParams.itemSurfaceTreatmentDesc" placeholder="请输入表面处理" clearable size="small" />
|
||||
</el-form-item>
|
||||
<el-form-item label="切边" prop="trimmingRequirement">
|
||||
<el-select v-model="queryParams.trimmingRequirement" placeholder="请选择切边" clearable style="width: 100%">
|
||||
<el-option label="净边" value="净边" />
|
||||
<el-option label="毛边" value="毛边" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="包装" prop="packagingRequirement">
|
||||
<el-select v-model="queryParams.packagingRequirement" placeholder="请选择包装" clearable style="width: 100%">
|
||||
<el-option label="裸包" value="裸包" />
|
||||
<el-option label="普包" value="普包" />
|
||||
<el-option label="简包" value="简包" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="品质">
|
||||
<muti-select v-model="queryParams.qualityStatusCsv" :options="dict.type.coil_quality_status"
|
||||
placeholder="请选择品质" clearable />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="showWaybill" label="发货状态">
|
||||
<el-radio-group v-model="queryParams.status" @change="handleQuery">
|
||||
<el-radio-button label="">全部</el-radio-button>
|
||||
@@ -1691,9 +1712,8 @@ export default {
|
||||
});
|
||||
},
|
||||
handleExportAll() {
|
||||
this.download('wms/materialCoil/export', {
|
||||
...this.queryParams
|
||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
const { orderBy, ...query } = this.queryParams;
|
||||
this.download('wms/materialCoil/export', query, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
/** 批量打印标签按钮 */
|
||||
handleBatchPrintLabel() {
|
||||
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
materialType: '成品',
|
||||
itemType: 'product',
|
||||
status: 0,
|
||||
orderBy: false
|
||||
orderBy: true
|
||||
},
|
||||
labelType: '3',
|
||||
showStatus: true,
|
||||
|
||||
@@ -38,10 +38,20 @@
|
||||
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="getList">查询</el-button>
|
||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
<!-- <el-button type="primary" @click="exportLossData">导出消耗钢卷</el-button> -->
|
||||
<el-button type="primary" @click="settingVisible = true">列设置</el-button>
|
||||
<!-- <el-button type="primary" @click="getList">查询</el-button> -->
|
||||
<el-dropdown split-button type="primary" @click="getList" @command="handleCommand">
|
||||
查询
|
||||
<el-dropdown-menu slot="dropdown">
|
||||
<el-dropdown-item command="exportData">导出产出钢卷</el-dropdown-item>
|
||||
<el-dropdown-item command="exportLossData">导出消耗钢卷</el-dropdown-item>
|
||||
<el-dropdown-item command="saveOutputReport">保存产出报表</el-dropdown-item>
|
||||
<el-dropdown-item command="saveLossReport">保存消耗报表</el-dropdown-item>
|
||||
</el-dropdown-menu>
|
||||
</el-dropdown>
|
||||
<!-- <el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
||||
<el-button type="primary" @click="exportLossData">导出消耗钢卷</el-button>
|
||||
<el-button type="primary" @click="saveOutputReport">保存产出报表</el-button>
|
||||
<el-button type="primary" @click="saveLossReport">保存消耗报表</el-button> -->
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
@@ -86,19 +96,24 @@
|
||||
<el-descriptions title="明细信息" :column="3" border>
|
||||
</el-descriptions>
|
||||
<el-tabs v-model="activeTab">
|
||||
<el-tab-pane label="投入钢卷" name="loss">
|
||||
<coil-table :data="lossList" :columns="lossColumns" :loading="loading" height="calc(100vh - 360px)" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="产出钢卷" name="output">
|
||||
<coil-table :data="outList" :columns="outputColumns" :loading="loading" height="calc(100vh - 360px)" />
|
||||
<coil-table :data="outList" :columns="outputColumns" :loading="loading" height="calc(100vh - 360px)">
|
||||
<template slot="settings">
|
||||
<el-button icon="el-icon-setting" @click="() => {settingVisible = true; activeColumnConfig = 'coil-report-output';}">列设置</el-button>
|
||||
</template>
|
||||
</coil-table>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="投入钢卷" name="loss">
|
||||
<coil-table :data="lossList" :columns="lossColumns" :loading="loading" height="calc(100vh - 360px)">
|
||||
<template slot="settings">
|
||||
<el-button icon="el-icon-setting" @click="() => {settingVisible = true; activeColumnConfig = 'coil-report-loss';}">列设置</el-button>
|
||||
</template>
|
||||
</coil-table>
|
||||
</el-tab-pane>
|
||||
|
||||
</el-tabs>
|
||||
|
||||
<el-dialog title="列设置" :visible.sync="settingVisible" width="50%">
|
||||
<el-radio-group v-model="activeColumnConfig">
|
||||
<!-- <el-radio-button label="coil-report-loss">投入明细配置</el-radio-button> -->
|
||||
<el-radio-button label="coil-report-output">产出明细配置</el-radio-button>
|
||||
</el-radio-group>
|
||||
<columns-setting :reportType="activeColumnConfig"></columns-setting>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -118,6 +133,7 @@ import { calcSummary, calcMSummary } from "@/views/wms/report/js/calc";
|
||||
import CoilTable from "@/views/wms/report/components/coilTable";
|
||||
import ColumnsSetting from "@/views/wms/report/components/setting/columns";
|
||||
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
||||
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
||||
|
||||
export default {
|
||||
name: 'MergeTemplate',
|
||||
@@ -182,8 +198,8 @@ export default {
|
||||
return {
|
||||
lossList: [],
|
||||
outList: [],
|
||||
activeTab: 'loss',
|
||||
activeColumnConfig: 'coil-report-loss',
|
||||
activeTab: 'output',
|
||||
activeColumnConfig: 'coil-report-output',
|
||||
settingVisible: false,
|
||||
loading: false,
|
||||
timeRangeParams: {
|
||||
@@ -201,7 +217,7 @@ export default {
|
||||
itemSpecification: '',
|
||||
itemMaterial: '',
|
||||
itemManufacturer: '',
|
||||
pageSize: 9999,
|
||||
pageSize: 99999,
|
||||
pageNum: 1,
|
||||
},
|
||||
lossColumns: [],
|
||||
@@ -243,6 +259,48 @@ export default {
|
||||
handleQuery() {
|
||||
this.getList()
|
||||
},
|
||||
// 保存产出报表
|
||||
saveOutputReport() {
|
||||
this.loading = true
|
||||
saveReportFile(this.outList.map(item => item.coilId).join(','), {
|
||||
reportParams: this.queryParams,
|
||||
reportType: '产出报表,异常报表',
|
||||
productionLine: this.productionLine,
|
||||
}).then(res => {
|
||||
this.$message({
|
||||
message: '保存成功',
|
||||
type: 'success',
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$message({
|
||||
message: '保存失败',
|
||||
type: 'error',
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
// 保存消耗报表
|
||||
saveLossReport() {
|
||||
this.loading = true
|
||||
saveReportFile(this.lossList.map(item => item.coilId).join(','), {
|
||||
reportParams: this.queryParams,
|
||||
reportType: '消耗报表,异常报表',
|
||||
productionLine: this.productionLine,
|
||||
}).then(res => {
|
||||
this.$message({
|
||||
message: '保存成功',
|
||||
type: 'success',
|
||||
})
|
||||
}).catch(err => {
|
||||
this.$message({
|
||||
message: '保存失败',
|
||||
type: 'error',
|
||||
})
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
async getList() {
|
||||
this.loading = true;
|
||||
const actions = await listPendingAction({ ...this.queryParams, actionTypes: this.actionTypes, actionStatus: 2 });
|
||||
@@ -282,68 +340,9 @@ export default {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// if (!lossIds) {
|
||||
// this.lossList = []
|
||||
// } else {
|
||||
// const lossRes = await listCoilWithIds({ ...this.queryParams, coilIds: lossIds || '', startTime: '', endTime: '' });
|
||||
|
||||
// this.lossList = lossRes.rows.map(item => {
|
||||
// // 计算宽度和厚度,将规格按照*分割,*前的是厚度,*后的是宽度
|
||||
// const [thickness, width] = item.specification?.split('*') || []
|
||||
// return {
|
||||
// ...item,
|
||||
// computedThickness: parseFloat(thickness),
|
||||
// computedWidth: parseFloat(width),
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
|
||||
this.loading = false;
|
||||
|
||||
// this.loading = true;
|
||||
// const res1 = await listPendingAction({ ...this.queryParams, actionTypes: '201,202,203,204,205,206', actionStatus: 2 });
|
||||
|
||||
// const res = res1.rows;
|
||||
// // 获取两层数据
|
||||
// const lossIds = res.map(item => item.coilId);
|
||||
// // 使用new Set去重
|
||||
// const outIds = [...new Set(res.map(item => item.processedCoilIds))];
|
||||
|
||||
// if (lossIds.length === 0 || outIds.length === 0) {
|
||||
// this.$message({
|
||||
// message: '查询结果为空',
|
||||
// type: 'warning'
|
||||
// })
|
||||
// this.loading = false;
|
||||
// return
|
||||
// }
|
||||
|
||||
// const [lossRes, outRes] = await Promise.all([
|
||||
// listCoilWithIds({ ...this.queryParams, coilIds: lossIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
// listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
// ]);
|
||||
// this.lossList = lossRes.rows.map(item => {
|
||||
// // 计算宽度和厚度,将规格按照*分割,*前的是厚度,*后的是宽度
|
||||
// const [thickness, width] = item.specification?.split('*') || []
|
||||
// return {
|
||||
// ...item,
|
||||
// computedThickness: parseFloat(thickness),
|
||||
// computedWidth: parseFloat(width),
|
||||
// }
|
||||
// });
|
||||
// this.outList = outRes.rows.map(item => {
|
||||
// // 计算宽度和厚度,将规格按照*分割,*前的是厚度,*后的是宽度
|
||||
// const [thickness, width] = item.specification?.split('*') || []
|
||||
// return {
|
||||
// ...item,
|
||||
// computedThickness: parseFloat(thickness),
|
||||
// computedWidth: parseFloat(width),
|
||||
// }
|
||||
// });
|
||||
// this.loading = false;
|
||||
},
|
||||
// 导出
|
||||
// 导出产出钢卷
|
||||
exportData() {
|
||||
if (this.outList.length === 0) {
|
||||
this.$message.warning('暂无数据可导出')
|
||||
@@ -353,6 +352,8 @@ export default {
|
||||
coilIds: this.outList.map(item => item.coilId).join(',')
|
||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
|
||||
// 导出消耗钢卷
|
||||
exportLossData() {
|
||||
if (this.lossList.length === 0) {
|
||||
this.$message.warning('暂无数据可导出')
|
||||
@@ -362,9 +363,21 @@ export default {
|
||||
coilIds: this.lossList.map(item => item.coilId).join(',')
|
||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
// 处理命令
|
||||
handleCommand(command) {
|
||||
if (command === 'exportData') {
|
||||
this.exportData()
|
||||
} else if (command === 'exportLossData') {
|
||||
this.exportLossData()
|
||||
} else if (command === 'saveOutputReport') {
|
||||
this.saveOutputReport()
|
||||
} else if (command === 'saveLossReport') {
|
||||
this.saveLossReport()
|
||||
}
|
||||
},
|
||||
// 加载列设置
|
||||
loadColumns() {
|
||||
// this.lossColumns = JSON.parse(localStorage.getItem('preference-tableColumns-coil-report-loss') || '[]') || []
|
||||
this.lossColumns = JSON.parse(localStorage.getItem('preference-tableColumns-coil-report-loss') || '[]') || []
|
||||
this.outputColumns = JSON.parse(localStorage.getItem('preference-tableColumns-coil-report-output') || '[]') || []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
<el-pagination layout="total, sizes, prev, pager, next, jumper" :total="total" :page-size.sync="pageSize"
|
||||
:page-sizes="[10, 20, 50, 100, 200, 500, 1000]" @size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange" />
|
||||
|
||||
<slot name="settings"></slot>
|
||||
</div>
|
||||
|
||||
<el-table :data="tableData" style="width: 100%" height="calc(100vh - 320px)" border row-key="coilId" :row-class-name="getRowClassName">
|
||||
|
||||
195
klp-ui/src/views/wms/report/components/crossTable/index.vue
Normal file
195
klp-ui/src/views/wms/report/components/crossTable/index.vue
Normal file
@@ -0,0 +1,195 @@
|
||||
<template>
|
||||
<el-table :data="tableData" border :style="{ width: '100%', marginBottom: '20px' }">
|
||||
<el-table-column :prop="config.rowField" :label="config.rowLabel" :width="config.rowWidth" align="center"
|
||||
fixed></el-table-column>
|
||||
|
||||
<template v-for="colVal in columnValues">
|
||||
<el-table-column :key="'group_' + colVal" :label="colVal + ''" align="center">
|
||||
<template v-for="summary in config.summaryColumns">
|
||||
<el-table-column :key="`${colVal}_${summary.prop}`" :label="summary.label" align="center">
|
||||
<template #default="scope">
|
||||
<!-- 强制显示值 -->
|
||||
<span>{{ scope.row[`${summary.prop}_${colVal}`] || '--' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
|
||||
<el-table-column label="合计" align="center">
|
||||
<template v-for="summary in config.summaryColumns">
|
||||
<el-table-column :key="'total_' + summary.prop" :prop="'total_' + summary.prop" :label="summary.label"
|
||||
:width="summary.width" align="center"></el-table-column>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'CrossTable',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 第一步:统计数据,生成行、列和单元格统计值
|
||||
statisticsData() {
|
||||
const {
|
||||
rowField,
|
||||
columnField,
|
||||
summaryColumns,
|
||||
formatKey
|
||||
} = this.config
|
||||
|
||||
const formatNum = (num) => {
|
||||
if (num === null || num === undefined) return null
|
||||
return parseFloat(num).toFixed(2)
|
||||
}
|
||||
|
||||
const formatKeyFn = formatKey || formatNum
|
||||
|
||||
// 数据结构:rowValues 行列表,colValues 列列表,cellStats[row][col][prop] = 统计值
|
||||
const rowValues = new Set()
|
||||
const colValues = new Set()
|
||||
const cellStats = new Map() // Map<rowKey, Map<colKey, { prop: value }>>
|
||||
|
||||
// 遍历原始数据,统计每个单元格
|
||||
this.data.forEach(item => {
|
||||
const colVal = item[columnField]
|
||||
const rowVal = item[rowField]
|
||||
|
||||
if (colVal != null && colVal !== '' && rowVal != null && rowVal !== '') {
|
||||
const colKey = formatKeyFn(colVal)
|
||||
const rowKey = formatKeyFn(rowVal)
|
||||
|
||||
rowValues.add(rowKey)
|
||||
colValues.add(colKey)
|
||||
|
||||
// 初始化单元格
|
||||
if (!cellStats.has(rowKey)) {
|
||||
cellStats.set(rowKey, new Map())
|
||||
}
|
||||
const rowStats = cellStats.get(rowKey)
|
||||
if (!rowStats.has(colKey)) {
|
||||
const initial = {}
|
||||
summaryColumns.forEach(sc => {
|
||||
initial[sc.prop] = 0
|
||||
})
|
||||
rowStats.set(colKey, initial)
|
||||
}
|
||||
const cell = rowStats.get(colKey)
|
||||
|
||||
// 累计统计值
|
||||
summaryColumns.forEach(sc => {
|
||||
if (sc.field === '') {
|
||||
cell[sc.prop] += 1
|
||||
} else {
|
||||
cell[sc.prop] += parseFloat(item[sc.field]) || 0
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// 排序并返回
|
||||
return {
|
||||
rowValues: Array.from(rowValues).map(v => parseFloat(v)).sort((a, b) => a - b).map(v => formatKeyFn(v)),
|
||||
colValues: Array.from(colValues).map(v => parseFloat(v)).sort((a, b) => a - b).map(v => formatKeyFn(v)),
|
||||
cellStats
|
||||
}
|
||||
},
|
||||
|
||||
// 第二步:根据统计数据生成 Element-UI Table 可用的数据
|
||||
tableData() {
|
||||
const {
|
||||
rowField,
|
||||
summaryColumns,
|
||||
formatValue
|
||||
} = this.config
|
||||
const { rowValues, colValues, cellStats } = this.statisticsData
|
||||
|
||||
// 生成每一行数据
|
||||
const rows = rowValues.map(rowKey => {
|
||||
const row = { [rowField]: parseFloat(rowKey) }
|
||||
const rowStats = cellStats.get(rowKey)
|
||||
const rowTotals = {}
|
||||
summaryColumns.forEach(sc => {
|
||||
rowTotals[sc.prop] = 0
|
||||
})
|
||||
|
||||
// 填充每一列的数据
|
||||
colValues.forEach(colKey => {
|
||||
const cell = rowStats?.get(colKey) || {}
|
||||
summaryColumns.forEach(sc => {
|
||||
const val = cell[sc.prop] || 0
|
||||
row[`${sc.prop}_${colKey}`] = formatValue ? formatValue(val, sc) : val.toFixed(3)
|
||||
rowTotals[sc.prop] += val
|
||||
})
|
||||
})
|
||||
|
||||
// 填充行合计
|
||||
summaryColumns.forEach(sc => {
|
||||
row[`total_${sc.prop}`] = formatValue ? formatValue(rowTotals[sc.prop], sc) : rowTotals[sc.prop].toFixed(3)
|
||||
})
|
||||
|
||||
return row
|
||||
})
|
||||
|
||||
// 在 tableData 计算属性中,生成 rows 后添加
|
||||
console.log('Generated row sample:', rows[0])
|
||||
console.log('Field names:', Object.keys(rows[0] || {}))
|
||||
console.log('rows length:', rows.length)
|
||||
console.log('colValues:', colValues)
|
||||
console.log('summaryColumns:', summaryColumns)
|
||||
|
||||
// 生成合计行
|
||||
const totalRow = { [rowField]: '合计' }
|
||||
const grandTotals = {}
|
||||
summaryColumns.forEach(sc => {
|
||||
grandTotals[sc.prop] = 0
|
||||
})
|
||||
|
||||
colValues.forEach(colKey => {
|
||||
const colTotals = {}
|
||||
summaryColumns.forEach(sc => {
|
||||
colTotals[sc.prop] = 0
|
||||
})
|
||||
|
||||
rows.forEach(row => {
|
||||
summaryColumns.forEach(sc => {
|
||||
const val = parseFloat(row[`${sc.prop}_${colKey}`]) || 0
|
||||
colTotals[sc.prop] += val
|
||||
grandTotals[sc.prop] += val
|
||||
})
|
||||
})
|
||||
|
||||
summaryColumns.forEach(sc => {
|
||||
totalRow[`${sc.prop}_${colKey}`] = formatValue ? formatValue(colTotals[sc.prop], sc) : colTotals[sc.prop].toFixed(3)
|
||||
})
|
||||
})
|
||||
|
||||
// 填充总合计
|
||||
summaryColumns.forEach(sc => {
|
||||
totalRow[`total_${sc.prop}`] = formatValue ? formatValue(grandTotals[sc.prop], sc) : grandTotals[sc.prop].toFixed(3)
|
||||
})
|
||||
|
||||
console.log(rows, 'rows')
|
||||
|
||||
return [...rows, totalRow]
|
||||
},
|
||||
|
||||
columnValues() {
|
||||
console.log(this.statisticsData.colValues, 'colValues')
|
||||
return this.statisticsData.colValues
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<el-table :data="tableData" border :style="{ width: '100%', marginBottom: '20px' }">
|
||||
<template v-for="(column, idx) in config.groupFields">
|
||||
<el-table-column
|
||||
:key="column"
|
||||
:prop="column"
|
||||
:label="config.groupLabels ? config.groupLabels[idx] : column"
|
||||
:align="config.groupAligns ? config.groupAligns[idx] : 'left'"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span :style="{
|
||||
paddingLeft: (scope.row.level * 20) + 'px',
|
||||
fontWeight: scope.row.level === idx ? 'bold' : 'normal'
|
||||
}">
|
||||
{{ scope.row[column] }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</template>
|
||||
<template v-for="summary in config.summaryFields">
|
||||
<el-table-column
|
||||
:key="summary.prop"
|
||||
:prop="summary.prop"
|
||||
:label="summary.label"
|
||||
:width="summary.width"
|
||||
:align="summary.align"
|
||||
></el-table-column>
|
||||
</template>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'HierarchicalPivot',
|
||||
props: {
|
||||
data: {
|
||||
type: Array,
|
||||
required: true
|
||||
},
|
||||
config: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
tableData() {
|
||||
const {
|
||||
groupFields,
|
||||
summaryFields,
|
||||
formatValue
|
||||
} = this.config
|
||||
|
||||
const buildHierarchy = (items, level = 0, parentKey = null) => {
|
||||
const result = []
|
||||
const field = groupFields[level]
|
||||
|
||||
if (!field) return result
|
||||
|
||||
const groupMap = new Map()
|
||||
items.forEach(item => {
|
||||
const key = item[field] || '未知'
|
||||
if (!groupMap.has(key)) {
|
||||
groupMap.set(key, [])
|
||||
}
|
||||
groupMap.get(key).push(item)
|
||||
})
|
||||
|
||||
const sortedKeys = Array.from(groupMap.keys()).sort()
|
||||
sortedKeys.forEach(key => {
|
||||
const groupItems = groupMap.get(key)
|
||||
const groupRow = {
|
||||
level,
|
||||
...groupFields.reduce((acc, f, idx) => {
|
||||
acc[f] = idx === level ? key : ''
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
summaryFields.forEach(sf => {
|
||||
let val
|
||||
if (sf.field === '') {
|
||||
val = groupItems.length
|
||||
} else {
|
||||
val = groupItems.reduce((acc, item) => {
|
||||
return acc + (parseFloat(item[sf.field]) || 0)
|
||||
}, 0)
|
||||
}
|
||||
groupRow[sf.prop] = formatValue ? formatValue(val, sf) : val.toFixed(3)
|
||||
})
|
||||
|
||||
result.push(groupRow)
|
||||
|
||||
if (level < groupFields.length - 1) {
|
||||
const children = buildHierarchy(groupItems, level + 1, key)
|
||||
result.push(...children)
|
||||
}
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
return buildHierarchy(this.data)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -21,6 +21,7 @@
|
||||
</div>
|
||||
<div class="quick-options">
|
||||
<el-button size="small" @click="setQuickTime('prevDay')">前一天</el-button>
|
||||
<el-button size="small" @click="setQuickTime('today')">今天</el-button>
|
||||
<el-button size="small" @click="setQuickTime('nextDay')">后一天</el-button>
|
||||
<el-button size="small" @click="setQuickTime('last7Days')">近7天</el-button>
|
||||
<el-button size="small" @click="setQuickTime('last15Days')">近15天</el-button>
|
||||
@@ -127,12 +128,15 @@ export default {
|
||||
|
||||
switch (type) {
|
||||
case 'prevDay':
|
||||
// 在当前时间基础上向前推一天
|
||||
newStartDate.setDate(newStartDate.getDate() - 1)
|
||||
newEndDate.setDate(newEndDate.getDate() - 1)
|
||||
break
|
||||
case 'today':
|
||||
const todayNow = new Date()
|
||||
newStartDate = todayNow
|
||||
newEndDate = todayNow
|
||||
break
|
||||
case 'nextDay':
|
||||
// 在当前时间基础上向后推一天
|
||||
newStartDate.setDate(newStartDate.getDate() + 1)
|
||||
newEndDate.setDate(newEndDate.getDate() + 1)
|
||||
break
|
||||
@@ -205,7 +209,11 @@ export default {
|
||||
}
|
||||
.quick-options {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
gap: 2px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.el-button + .el-button {
|
||||
margin-left: 4px
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -62,6 +62,12 @@
|
||||
<el-descriptions-item label="均重">{{ summary.avgWeight }}t</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
|
||||
<!-- 厂家材质透视表 -->
|
||||
<HierarchicalPivot :data="list" :config="hierarchicalPivotConfig" />
|
||||
|
||||
<!-- 宽度厚度统计表 -->
|
||||
<CrossTable :data="list" :config="crossTableConfig" />
|
||||
|
||||
<el-descriptions title="明细信息" :column="3" border>
|
||||
</el-descriptions>
|
||||
<coil-table :columns="receiveColumns" :data="list"></coil-table>
|
||||
@@ -90,6 +96,8 @@ import { listDeliveryPlan } from '@/api/wms/deliveryPlan'
|
||||
import ColumnsSetting from "@/views/wms/report/components/setting/columns.vue";
|
||||
import CoilTable from "@/views/wms/report/components/coilTable/index.vue";
|
||||
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
||||
import HierarchicalPivot from "@/views/wms/report/components/hierarchicalPivot/index.vue";
|
||||
import CrossTable from "@/views/wms/report/components/crossTable/index.vue";
|
||||
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
||||
|
||||
|
||||
@@ -104,12 +112,13 @@ export default {
|
||||
ColumnsSetting,
|
||||
CoilTable,
|
||||
TimeRangePicker,
|
||||
HierarchicalPivot,
|
||||
CrossTable,
|
||||
},
|
||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||
data() {
|
||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||
const addZero = (num) => num.toString().padStart(2, '0')
|
||||
|
||||
const now = new Date() // 当前本地北京时间
|
||||
// 核心:获取【昨天】的日期对象(自动处理跨月/跨年,无边界问题)
|
||||
const yesterday = new Date(now)
|
||||
@@ -151,6 +160,44 @@ export default {
|
||||
loading: false,
|
||||
|
||||
receiveColumns: [],
|
||||
|
||||
// 厂家材质透视表配置
|
||||
hierarchicalPivotConfig: {
|
||||
groupFields: ['manufacturer', 'material'],
|
||||
groupLabels: ['厂家', '材质'],
|
||||
summaryFields: [
|
||||
{ prop: 'count', label: '求和项:件数', field: '', align: 'center' },
|
||||
{ prop: 'weight', label: '求和项:重量', field: 'netWeight', align: 'center' }
|
||||
],
|
||||
formatValue: (value, summaryField) => {
|
||||
if (summaryField.field === '') {
|
||||
return value
|
||||
}
|
||||
return value.toFixed(3)
|
||||
}
|
||||
},
|
||||
|
||||
// 宽度厚度统计表配置
|
||||
crossTableConfig: {
|
||||
rowField: 'computedWidth',
|
||||
rowLabel: '宽度',
|
||||
rowWidth: 100,
|
||||
columnField: 'computedThickness',
|
||||
summaryColumns: [
|
||||
{ prop: 'count', label: '件数', width: 80, field: '' },
|
||||
{ prop: 'weight', label: '重量', width: 100, field: 'netWeight' }
|
||||
],
|
||||
formatValue: (value, summaryField) => {
|
||||
if (summaryField.field === '') {
|
||||
return value
|
||||
}
|
||||
return value.toFixed(2)
|
||||
},
|
||||
formatKey: (num) => {
|
||||
if (num === null || num === undefined || isNaN(num)) return null
|
||||
return parseFloat(num).toFixed(2)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -167,7 +214,8 @@ export default {
|
||||
},
|
||||
coilIds() {
|
||||
return this.list.map(item => item.coilId).join(',')
|
||||
}
|
||||
},
|
||||
|
||||
},
|
||||
methods: {
|
||||
// 加载列设置
|
||||
@@ -196,7 +244,6 @@ export default {
|
||||
}).then(res => {
|
||||
const actions = res.rows
|
||||
const coilIds = actions.map(item => item.coilId).join(',')
|
||||
console.log(coilIds)
|
||||
if (!coilIds) {
|
||||
this.$message({
|
||||
message: '暂无数据',
|
||||
|
||||
@@ -452,7 +452,6 @@ export default {
|
||||
this.lossList = lossList.filter(item => !this.mergeCoils.includes(item.coilId))
|
||||
// 找出所有被剔除的卷的id,
|
||||
const removedCoilIds = lossList.filter(item => this.mergeCoils.includes(item.coilId)).map(item => item.coilId)
|
||||
console.log(removedCoilIds)
|
||||
this.list = outputList.filter(item => !removedCoilIds.includes(item.parentCoilId))
|
||||
// if (this.viewType == 'day') {
|
||||
// this.getYesterdayData()
|
||||
|
||||
Reference in New Issue
Block a user