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">
|
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态"
|
<!-- <el-select v-model="scope.row.actionStatus" placeholder="请选择操作状态"
|
||||||
@change="handleStatusChange(scope.row)">
|
@change="handleStatusChange(scope.row)">
|
||||||
<el-option label="待处理" :value="0" />
|
<el-option label="待处理" :value="0" />
|
||||||
<el-option label="处理中" :value="1" />
|
<el-option label="处理中" :value="1" />
|
||||||
<el-option label="已完成" :value="2" />
|
<el-option label="已完成" :value="2" />
|
||||||
<el-option label="已取消" :value="3" />
|
<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>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|||||||
@@ -72,12 +72,16 @@
|
|||||||
|
|
||||||
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
|
<el-table-column label="操作状态" align="center" prop="actionStatus" width="120">
|
||||||
<template slot-scope="scope">
|
<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="0" />
|
||||||
<el-option label="处理中" :value="1" />
|
<el-option label="处理中" :value="1" />
|
||||||
<el-option label="已完成" :value="2" />
|
<el-option label="已完成" :value="2" />
|
||||||
<el-option label="已取消" :value="3" />
|
<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>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,27 @@
|
|||||||
clearable @keyup.enter.native="handleQuery" />
|
clearable @keyup.enter.native="handleQuery" />
|
||||||
</el-form-item>
|
</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-form-item v-if="showWaybill" label="发货状态">
|
||||||
<el-radio-group v-model="queryParams.status" @change="handleQuery">
|
<el-radio-group v-model="queryParams.status" @change="handleQuery">
|
||||||
<el-radio-button label="">全部</el-radio-button>
|
<el-radio-button label="">全部</el-radio-button>
|
||||||
@@ -1691,9 +1712,8 @@ export default {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleExportAll() {
|
handleExportAll() {
|
||||||
this.download('wms/materialCoil/export', {
|
const { orderBy, ...query } = this.queryParams;
|
||||||
...this.queryParams
|
this.download('wms/materialCoil/export', query, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
|
||||||
},
|
},
|
||||||
/** 批量打印标签按钮 */
|
/** 批量打印标签按钮 */
|
||||||
handleBatchPrintLabel() {
|
handleBatchPrintLabel() {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export default {
|
|||||||
materialType: '成品',
|
materialType: '成品',
|
||||||
itemType: 'product',
|
itemType: 'product',
|
||||||
status: 0,
|
status: 0,
|
||||||
orderBy: false
|
orderBy: true
|
||||||
},
|
},
|
||||||
labelType: '3',
|
labelType: '3',
|
||||||
showStatus: true,
|
showStatus: true,
|
||||||
|
|||||||
@@ -38,10 +38,20 @@
|
|||||||
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
:options="dict.type.coil_manufacturer" placeholder="请选择厂家" clearable @keyup.enter.native="handleQuery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="getList">查询</el-button>
|
<!-- <el-button type="primary" @click="getList">查询</el-button> -->
|
||||||
<el-button type="primary" @click="exportData">导出产出钢卷</el-button>
|
<el-dropdown split-button type="primary" @click="getList" @command="handleCommand">
|
||||||
<!-- <el-button type="primary" @click="exportLossData">导出消耗钢卷</el-button> -->
|
查询
|
||||||
<el-button type="primary" @click="settingVisible = true">列设置</el-button>
|
<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-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -86,19 +96,24 @@
|
|||||||
<el-descriptions title="明细信息" :column="3" border>
|
<el-descriptions title="明细信息" :column="3" border>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<el-tabs v-model="activeTab">
|
<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">
|
<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>
|
||||||
|
<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-tabs>
|
||||||
|
|
||||||
<el-dialog title="列设置" :visible.sync="settingVisible" width="50%">
|
<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>
|
<columns-setting :reportType="activeColumnConfig"></columns-setting>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
@@ -118,6 +133,7 @@ import { calcSummary, calcMSummary } from "@/views/wms/report/js/calc";
|
|||||||
import CoilTable from "@/views/wms/report/components/coilTable";
|
import CoilTable from "@/views/wms/report/components/coilTable";
|
||||||
import ColumnsSetting from "@/views/wms/report/components/setting/columns";
|
import ColumnsSetting from "@/views/wms/report/components/setting/columns";
|
||||||
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.vue";
|
||||||
|
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MergeTemplate',
|
name: 'MergeTemplate',
|
||||||
@@ -182,8 +198,8 @@ export default {
|
|||||||
return {
|
return {
|
||||||
lossList: [],
|
lossList: [],
|
||||||
outList: [],
|
outList: [],
|
||||||
activeTab: 'loss',
|
activeTab: 'output',
|
||||||
activeColumnConfig: 'coil-report-loss',
|
activeColumnConfig: 'coil-report-output',
|
||||||
settingVisible: false,
|
settingVisible: false,
|
||||||
loading: false,
|
loading: false,
|
||||||
timeRangeParams: {
|
timeRangeParams: {
|
||||||
@@ -201,7 +217,7 @@ export default {
|
|||||||
itemSpecification: '',
|
itemSpecification: '',
|
||||||
itemMaterial: '',
|
itemMaterial: '',
|
||||||
itemManufacturer: '',
|
itemManufacturer: '',
|
||||||
pageSize: 9999,
|
pageSize: 99999,
|
||||||
pageNum: 1,
|
pageNum: 1,
|
||||||
},
|
},
|
||||||
lossColumns: [],
|
lossColumns: [],
|
||||||
@@ -243,6 +259,48 @@ export default {
|
|||||||
handleQuery() {
|
handleQuery() {
|
||||||
this.getList()
|
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() {
|
async getList() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
const actions = await listPendingAction({ ...this.queryParams, actionTypes: this.actionTypes, actionStatus: 2 });
|
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 = 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() {
|
exportData() {
|
||||||
if (this.outList.length === 0) {
|
if (this.outList.length === 0) {
|
||||||
this.$message.warning('暂无数据可导出')
|
this.$message.warning('暂无数据可导出')
|
||||||
@@ -353,6 +352,8 @@ export default {
|
|||||||
coilIds: this.outList.map(item => item.coilId).join(',')
|
coilIds: this.outList.map(item => item.coilId).join(',')
|
||||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 导出消耗钢卷
|
||||||
exportLossData() {
|
exportLossData() {
|
||||||
if (this.lossList.length === 0) {
|
if (this.lossList.length === 0) {
|
||||||
this.$message.warning('暂无数据可导出')
|
this.$message.warning('暂无数据可导出')
|
||||||
@@ -362,9 +363,21 @@ export default {
|
|||||||
coilIds: this.lossList.map(item => item.coilId).join(',')
|
coilIds: this.lossList.map(item => item.coilId).join(',')
|
||||||
}, `materialCoil_${new Date().getTime()}.xlsx`)
|
}, `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() {
|
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') || '[]') || []
|
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"
|
<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"
|
:page-sizes="[10, 20, 50, 100, 200, 500, 1000]" @size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange" />
|
@current-change="handleCurrentChange" />
|
||||||
|
|
||||||
|
<slot name="settings"></slot>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-table :data="tableData" style="width: 100%" height="calc(100vh - 320px)" border row-key="coilId" :row-class-name="getRowClassName">
|
<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>
|
||||||
<div class="quick-options">
|
<div class="quick-options">
|
||||||
<el-button size="small" @click="setQuickTime('prevDay')">前一天</el-button>
|
<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('nextDay')">后一天</el-button>
|
||||||
<el-button size="small" @click="setQuickTime('last7Days')">近7天</el-button>
|
<el-button size="small" @click="setQuickTime('last7Days')">近7天</el-button>
|
||||||
<el-button size="small" @click="setQuickTime('last15Days')">近15天</el-button>
|
<el-button size="small" @click="setQuickTime('last15Days')">近15天</el-button>
|
||||||
@@ -127,12 +128,15 @@ export default {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'prevDay':
|
case 'prevDay':
|
||||||
// 在当前时间基础上向前推一天
|
|
||||||
newStartDate.setDate(newStartDate.getDate() - 1)
|
newStartDate.setDate(newStartDate.getDate() - 1)
|
||||||
newEndDate.setDate(newEndDate.getDate() - 1)
|
newEndDate.setDate(newEndDate.getDate() - 1)
|
||||||
break
|
break
|
||||||
|
case 'today':
|
||||||
|
const todayNow = new Date()
|
||||||
|
newStartDate = todayNow
|
||||||
|
newEndDate = todayNow
|
||||||
|
break
|
||||||
case 'nextDay':
|
case 'nextDay':
|
||||||
// 在当前时间基础上向后推一天
|
|
||||||
newStartDate.setDate(newStartDate.getDate() + 1)
|
newStartDate.setDate(newStartDate.getDate() + 1)
|
||||||
newEndDate.setDate(newEndDate.getDate() + 1)
|
newEndDate.setDate(newEndDate.getDate() + 1)
|
||||||
break
|
break
|
||||||
@@ -205,7 +209,11 @@ export default {
|
|||||||
}
|
}
|
||||||
.quick-options {
|
.quick-options {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 2px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.el-button + .el-button {
|
||||||
|
margin-left: 4px
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -62,6 +62,12 @@
|
|||||||
<el-descriptions-item label="均重">{{ summary.avgWeight }}t</el-descriptions-item>
|
<el-descriptions-item label="均重">{{ summary.avgWeight }}t</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
|
|
||||||
|
<!-- 厂家材质透视表 -->
|
||||||
|
<HierarchicalPivot :data="list" :config="hierarchicalPivotConfig" />
|
||||||
|
|
||||||
|
<!-- 宽度厚度统计表 -->
|
||||||
|
<CrossTable :data="list" :config="crossTableConfig" />
|
||||||
|
|
||||||
<el-descriptions title="明细信息" :column="3" border>
|
<el-descriptions title="明细信息" :column="3" border>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<coil-table :columns="receiveColumns" :data="list"></coil-table>
|
<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 ColumnsSetting from "@/views/wms/report/components/setting/columns.vue";
|
||||||
import CoilTable from "@/views/wms/report/components/coilTable/index.vue";
|
import CoilTable from "@/views/wms/report/components/coilTable/index.vue";
|
||||||
import TimeRangePicker from "@/views/wms/report/components/timeRangePicker.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";
|
import { saveReportFile } from "@/views/wms/report/js/reportFile";
|
||||||
|
|
||||||
|
|
||||||
@@ -104,12 +112,13 @@ export default {
|
|||||||
ColumnsSetting,
|
ColumnsSetting,
|
||||||
CoilTable,
|
CoilTable,
|
||||||
TimeRangePicker,
|
TimeRangePicker,
|
||||||
|
HierarchicalPivot,
|
||||||
|
CrossTable,
|
||||||
},
|
},
|
||||||
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
dicts: ['product_coil_status', 'coil_material', 'coil_itemname', 'coil_manufacturer'],
|
||||||
data() {
|
data() {
|
||||||
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
// 工具函数:个位数补零,保证格式统一(比如 9 → 09,5 → 05)
|
||||||
const addZero = (num) => num.toString().padStart(2, '0')
|
const addZero = (num) => num.toString().padStart(2, '0')
|
||||||
|
|
||||||
const now = new Date() // 当前本地北京时间
|
const now = new Date() // 当前本地北京时间
|
||||||
// 核心:获取【昨天】的日期对象(自动处理跨月/跨年,无边界问题)
|
// 核心:获取【昨天】的日期对象(自动处理跨月/跨年,无边界问题)
|
||||||
const yesterday = new Date(now)
|
const yesterday = new Date(now)
|
||||||
@@ -151,6 +160,44 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
|
|
||||||
receiveColumns: [],
|
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: {
|
computed: {
|
||||||
@@ -167,7 +214,8 @@ export default {
|
|||||||
},
|
},
|
||||||
coilIds() {
|
coilIds() {
|
||||||
return this.list.map(item => item.coilId).join(',')
|
return this.list.map(item => item.coilId).join(',')
|
||||||
}
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 加载列设置
|
// 加载列设置
|
||||||
@@ -196,7 +244,6 @@ export default {
|
|||||||
}).then(res => {
|
}).then(res => {
|
||||||
const actions = res.rows
|
const actions = res.rows
|
||||||
const coilIds = actions.map(item => item.coilId).join(',')
|
const coilIds = actions.map(item => item.coilId).join(',')
|
||||||
console.log(coilIds)
|
|
||||||
if (!coilIds) {
|
if (!coilIds) {
|
||||||
this.$message({
|
this.$message({
|
||||||
message: '暂无数据',
|
message: '暂无数据',
|
||||||
|
|||||||
@@ -452,7 +452,6 @@ export default {
|
|||||||
this.lossList = lossList.filter(item => !this.mergeCoils.includes(item.coilId))
|
this.lossList = lossList.filter(item => !this.mergeCoils.includes(item.coilId))
|
||||||
// 找出所有被剔除的卷的id,
|
// 找出所有被剔除的卷的id,
|
||||||
const removedCoilIds = lossList.filter(item => this.mergeCoils.includes(item.coilId)).map(item => item.coilId)
|
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))
|
this.list = outputList.filter(item => !removedCoilIds.includes(item.parentCoilId))
|
||||||
// if (this.viewType == 'day') {
|
// if (this.viewType == 'day') {
|
||||||
// this.getYesterdayData()
|
// this.getYesterdayData()
|
||||||
|
|||||||
Reference in New Issue
Block a user