This commit is contained in:
tzy 2025-09-14 22:42:39 +08:00
parent 9c0d5a65a8
commit 90f8bfe677
4 changed files with 2190 additions and 0 deletions

128
src/api/system/mrp.js Normal file
View File

@ -0,0 +1,128 @@
import request from '@/utils/request'
// 查询MRP运算结果复查列表
export function listMrp(query) {
return request({
url: '/system/mrp/list',
method: 'get',
params: query
})
}
// 查询MRP运算结果复查详细
export function getMrp(id) {
return request({
url: '/system/mrp/' + id,
method: 'get'
})
}
// 新增MRP运算结果复查
export function addMrp(data) {
return request({
url: '/system/mrp',
method: 'post',
data: data
})
}
// 修改MRP运算结果复查
export function updateMrp(data) {
return request({
url: '/system/mrp',
method: 'put',
data: data
})
}
// 删除MRP运算结果复查
export function delMrp(id) {
return request({
url: '/system/mrp/' + id,
method: 'delete'
})
}
// 导出MRP运算结果复查列表
export function exportMrp(query) {
return request({
url: '/system/mrp/export',
method: 'post',
data: query,
responseType: 'blob',
timeout: 5 * 60 * 1000 // 导出可能需要较长时间设置5分钟超时
})
}
// ========== MRP2 相关方法 ==========
// 查询MRP2运算结果列表
export function getMRP2Results(query) {
return request({
url: '/system/mrp2/list',
method: 'get',
params: query
})
}
// 查询MRP2运算结果详细
export function getMRP2Result(id) {
return request({
url: '/system/mrp2/' + id,
method: 'get'
})
}
// 新增MRP2运算结果
export function addMRP2Result(data) {
return request({
url: '/system/mrp2',
method: 'post',
data: data
})
}
// 修改MRP2运算结果
export function updateMRP2Result(data) {
return request({
url: '/system/mrp2',
method: 'put',
data: data
})
}
// 删除MRP2运算结果
export function delMRP2Result(id) {
return request({
url: '/system/mrp2/' + id,
method: 'delete'
})
}
// 导出MRP2运算结果
export function exportMRP2Data(query) {
return request({
url: '/system/mrp2/export',
method: 'post',
data: query,
responseType: 'blob'
})
}
// 执行MRP2运算
export function executeMRP2Calculation(data) {
return request({
url: '/system/mrp2/calculate',
method: 'post',
data: data
})
}
// 获取MRP2统计信息
export function getMRP2Stats(query) {
return request({
url: '/system/mrp2/stats',
method: 'get',
params: query
})
}

67
src/api/system/proPlan.js Normal file
View File

@ -0,0 +1,67 @@
import request from '@/utils/request'
// 查询方案管理列表
export function listProPlan(query) {
return request({
url: '/system/proPlan/list',
method: 'get',
params: query
})
}// 查询方案管理列表
export function listProPlan2(query) {
return request({
url: '/system/proPlan/list2',
method: 'get',
params: query
})
}
// 查询超期/临期项目列表
export function listProPlanOverdue() {
return request({
url: '/system/proPlan/overdue',
method: 'get'
})
}
// 查询临期项目列表
export function listProPlanExpirys() {
return request({
url: '/system/proPlan/expiryProjects',
method: 'get'
})
}
// 查询方案管理详细
export function getProPlan(id) {
return request({
url: '/system/proPlan/' + id,
method: 'get'
})
}
// 新增方案管理
export function addProPlan(data) {
return request({
url: '/system/proPlan',
method: 'post',
data: data
})
}
// 修改方案管理
export function updateProPlan(data) {
return request({
url: '/system/proPlan',
method: 'put',
data: data
})
}
// 删除方案管理
export function delProPlan(id) {
return request({
url: '/system/proPlan/' + id,
method: 'delete'
})
}

1050
src/views/indexDaping.vue Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,945 @@
<template>
<div class="mrp2-standalone-container">
<!-- 独立页面头部 -->
<div class="standalone-header">
<div class="header-content">
<div class="header-left">
<h1 style="margin: 0; color: #303133; font-size: 24px;">
<i class="el-icon-data-analysis" style="margin-right: 12px; color: #409EFF;"></i>
项目供需查询(仅供参考)
</h1>
<p style="margin: 8px 0 0 0; color: #909399; font-size: 14px;">
物料需求计划运算结果查询
</p>
</div>
<div class="header-right">
<el-button type="primary" icon="el-icon-refresh" @click="handleRefreshAll">
刷新页面
</el-button>
<el-button type="info" icon="el-icon-back" @click="goBack">
返回
</el-button>
</div>
</div>
</div>
<!-- 页面内容 -->
<div class="page-content">
<!-- 查询条件 -->
<el-card class="box-card" style="margin-bottom: 20px;">
<div slot="header" class="clearfix">
<span style="font-weight: 600; color: #303133;">
<i class="el-icon-search" style="margin-right: 8px; color: #409EFF;"></i>
查询条件
</span>
</div>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="100px">
<el-form-item label="生产令号" prop="productionOrderNo">
<el-select
v-model="productionObj"
placeholder="请选择生产令号"
clearable
filterable
style="width: 400px"
@change="handleProductionOrderChange"
value-key="id"
:loading="productionOrderLoading"
:filter-method="filterProductionOrders"
remote
reserve-keyword
popper-class="production-order-select-dropdown"
>
<el-option
v-for="item in filteredProductionOrderList"
:key="item.id"
:value="item"
>
<div style="display: flex; justify-content: space-between; align-items: center; min-height: 40px; padding: 4px 0;">
<div style="flex: 1; min-width: 0;">
<div style="font-weight: 600; color: #303133; font-size: 14px; line-height: 1.4; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" :title="item.productionOrderNo">
{{ item.productionOrderNo }}
</div>
<div style="color: #909399; font-size: 12px; margin-top: 2px; line-height: 1.3; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" :title="item.productionName">
{{ item.productionName }}
</div>
</div>
<div style="text-align: right; margin-left: 12px; flex-shrink: 0; display: flex; flex-direction: column; align-items: flex-end;">
<el-tag
v-if="item.drawingNo"
size="mini"
type="info"
style="margin-bottom: 2px; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;"
:title="item.drawingNo"
>
{{ item.drawingNo }}
</el-tag>
<div style="color: #67c23a; font-size: 11px; line-height: 1.2; max-width: 100px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;" :title="item.createdBy || '系统'">
{{ item.createdBy || '系统' }}
</div>
</div>
</div>
</el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
<!-- 当前选择的生产令号信息 -->
<el-card v-if="productionObj" class="box-card production-order-info" style="margin-bottom: 20px;">
<div slot="header" class="clearfix">
<span style="font-weight: 600; color: #303133;">
<i class="el-icon-document" style="margin-right: 8px; color: #409EFF;"></i>
当前选择的生产令号
</span>
</div>
<div style="display: flex; align-items: center; gap: 20px; padding: 10px 0;">
<div style="flex: 1;">
<div style="display: flex; align-items: center; gap: 12px;">
<el-tag type="primary" size="medium" style="font-weight: 600;">
{{ productionObj.productionOrderNo }}
</el-tag>
<span style="font-size: 16px; font-weight: 600; color: #303133;">
{{ productionObj.productionName }}
</span>
</div>
<div style="margin-top: 8px; display: flex; gap: 16px; font-size: 13px; color: #606266;">
<span v-if="productionObj.drawingNo">
<i class="el-icon-document-copy" style="margin-right: 4px;"></i>
图号: {{ productionObj.drawingNo }}
</span>
<span v-if="productionObj.createdBy">
<i class="el-icon-user" style="margin-right: 4px;"></i>
创建人: {{ productionObj.createdBy }}
</span>
<span v-if="productionObj.createTime">
<i class="el-icon-time" style="margin-right: 4px;"></i>
创建时间: {{ formatDateTime(productionObj.createTime) }}
</span>
</div>
</div>
<div>
<el-button
type="text"
icon="el-icon-refresh"
@click="handleRefreshMrpData"
:loading="mrpLoading"
>
刷新数据
</el-button>
</div>
</div>
</el-card>
<!-- MRP运算结果 -->
<el-card class="box-card mrp-result-card" style="margin-bottom: 20px;">
<div slot="header" class="clearfix">
<span style="font-weight: 600; color: #303133;">
<i class="el-icon-data-analysis" style="margin-right: 8px; color: #409EFF;"></i>
运算结果
</span>
<div style="float: right; display: flex; align-items: center; gap: 12px;">
<!-- 运算状态显示 -->
<div v-if="loadingMRP" class="mrp-status-indicator">
<i class="el-icon-loading" style="margin-right: 6px;"></i>
<span>{{ mrpOperationStatus || '运算进行中...' }}</span>
</div>
<!-- 运算结果按钮 -->
<el-button
type="primary"
size="medium"
:loading="loadingMRP"
:disabled="loadingMRP"
@click="getMRPResults()"
class="mrp-calculate-btn"
>
{{ loadingMRP ? '核算中...' : '开始核算' }}
</el-button>
<!-- 搜索输入框 -->
<el-input
v-model="mrpSearchKeyword"
placeholder="搜索物料名称或编码"
style="width: 220px;"
size="small"
clearable
@input="handleMrpSearch"
@clear="clearMrpSearch"
class="mrp-search-input"
>
<i slot="prefix" class="el-input__icon el-icon-search"></i>
</el-input>
<!-- 导出按钮 -->
<el-button
type="success"
size="small"
icon="el-icon-download"
@click="handleExportMrp"
:loading="exportLoading"
:disabled="!productionObj || !productionObj.id"
class="mrp-export-btn"
:title="productionObj && productionObj.id ? `导出${productionObj.productionOrderNo}的MRP数据` : '请先选择生产令号'"
>
导出Excel
</el-button>
<el-button type="text" @click="handleRefreshMrpData">
<i class="el-icon-refresh"></i> 刷新
</el-button>
</div>
</div>
<!-- 统计信息 -->
<div
v-if="productionObj"
style="margin-bottom: 15px; padding: 15px; background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%); border-radius: 8px; border-left: 4px solid #409EFF;">
<el-row :gutter="20">
<el-col :span="6">
<div style="text-align: center;">
<div style="font-size: 24px; font-weight: bold; color: #409EFF;">{{ mrpStats.totalMaterials }}</div>
<div style="font-size: 12px; color: #606266;">总物料数</div>
</div>
</el-col>
<el-col :span="6">
<div style="text-align: center;">
<div style="font-size: 24px; font-weight: bold; color: #67c23a;">{{ mrpStats.positiveStock }}</div>
<div style="font-size: 12px; color: #606266;">正库存</div>
</div>
</el-col>
<el-col :span="6">
<div style="text-align: center;">
<div style="font-size: 24px; font-weight: bold; color: #f56c6c;">{{ mrpStats.negativeStock }}</div>
<div style="font-size: 12px; color: #606266;">负库存</div>
</div>
</el-col>
<el-col :span="6">
<div style="text-align: center;">
<div style="font-size: 24px; font-weight: bold; color: #e6a23c;">{{ mrpStats.zeroStock }}</div>
<div style="font-size: 12px; color: #606266;">零库存</div>
</div>
</el-col>
</el-row>
</div>
<!-- 提示信息 -->
<div v-if="!productionObj" style="text-align: center; padding: 40px; color: #909399;">
<i class="el-icon-info" style="font-size: 48px; margin-bottom: 16px;"></i>
<p style="font-size: 16px; margin: 0;">请先选择生产令号以查看运算结果</p>
</div>
<el-table
v-else
:data="mrpResultData"
style="width: 100%"
:header-cell-style="{ background: '#f5f7fa', color: '#606266' }"
:row-class-name="getMrpRowClass"
border
stripe
size="small"
v-loading="mrpLoading"
>
<el-table-column prop="materialCode" label="物料编码" min-width="120" show-overflow-tooltip/>
<el-table-column prop="materialName" label="物料名称" min-width="100" show-overflow-tooltip/>
<el-table-column prop="purchaseNotInStock" label="项目本批数" width="130" align="right">
<template slot-scope="scope">
<span style="color: #e6a23c">{{ scope.row.purchaseNotInStock.toFixed(2) }}</span>
</template>
</el-table-column>
<el-table-column prop="availableStock" label="本项目可用库存" width="120" align="right">
<template slot-scope="scope">
<span :style="{ color: scope.row.availableStock < 0 ? '#f56c6c' : '#67c23a' }">
{{ scope.row.availableStock.toFixed(3) }}
</span>
</template>
</el-table-column>
<el-table-column prop="realTimeStock" label="当前可用库存" width="100" align="right">
<template slot-scope="scope">
<span :style="{ color: scope.row.realTimeStock < 0 ? '#f56c6c' : '#67c23a' }">
{{ scope.row.realTimeStock.toFixed(3) }}
</span>
</template>
</el-table-column>
<el-table-column prop="prodNotInStock" label="本次生产未入库" width="130" align="right">
<template slot-scope="scope">
<span style="color: #e6a23c">{{ scope.row.prodNotInStock.toFixed(3) }}</span>
</template>
</el-table-column>
<el-table-column prop="purchaseRequestQty" label="本项目采购申请" width="130" align="right">
<template slot-scope="scope">
<span style="color: #409eff">{{ scope.row.purchaseRequestQty.toFixed(3) }}</span>
</template>
</el-table-column>
<el-table-column prop="childNotPickedQty" label="子项未领料数量" width="130" align="right">
<template slot-scope="scope">
<span style="color: #f56c6c">{{ scope.row.childNotPickedQty.toFixed(3) }}</span>
</template>
</el-table-column>
<el-table-column prop="createTime" label="创建时间" width="160" align="center">
<template slot-scope="scope">
{{ formatDateTime(scope.row.createTime) }}
</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间" width="160" align="center">
<template slot-scope="scope">
{{ formatDateTime(scope.row.updateTime) }}
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-if="productionObj"
@size-change="handleMrpSizeChange"
@current-change="handleMrpCurrentChange"
:current-page="mrpQueryParams.pageNum"
:page-sizes="[10, 50, 100, 500]"
:page-size="mrpQueryParams.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="mrpTotal"
style="margin-top: 20px; text-align: right;"
/>
</el-card>
</div>
</div>
</template>
<script>
import { listMrp, exportMrp } from '@/api/system/mrp'
import { listOrderPro, getMRPResults } from '@/api/system/orderPro'
import dayjs from "dayjs"
export default {
name: "MRPIndex",
data() {
return {
//
queryParams: {
pageNum: 1,
pageSize: 10,
productionOrderNo: null,
materialCode: null,
materialName: null
},
showSearch: true,
// orderProproductionObj
productionObj: null,
productionOrderList: [], //
filteredProductionOrderList: [], //
productionOrderLoading: false, //
// MRPorderProMRP
mrpResultData: [],
mrpLoading: false,
mrpTotal: 0,
mrpSearchKeyword: '',
mrpQueryParams: {
pageNum: 1,
pageSize: 10,
materialName: '',
materialCode: '',
orderProId: null
},
loadingMRP: false,
mrpOperationStatus: '', // MRP
exportLoading: false, //
mrpStats: {
totalMaterials: 0,
positiveStock: 0,
negativeStock: 0,
zeroStock: 0
}
}
},
created() {
this.getProductionOrderList()
},
methods: {
/** 获取生产令号列表 */
async getProductionOrderList() {
this.productionOrderLoading = true
try {
const response = await listOrderPro({
pageNum: 1,
pageSize: 1000 //
})
if (response && response.rows) {
this.productionOrderList = response.rows
this.filteredProductionOrderList = response.rows
} else {
this.productionOrderList = []
this.filteredProductionOrderList = []
}
} catch (error) {
console.error('获取生产令号列表失败:', error)
this.$message.error('获取生产令号列表失败')
this.productionOrderList = []
this.filteredProductionOrderList = []
} finally {
this.productionOrderLoading = false
}
},
/** 过滤生产令号 */
filterProductionOrders(query) {
if (!query) {
this.filteredProductionOrderList = this.productionOrderList
return
}
const keyword = query.toLowerCase()
this.filteredProductionOrderList = this.productionOrderList.filter(item =>
item.productionOrderNo.toLowerCase().includes(keyword) ||
item.productionName.toLowerCase().includes(keyword) ||
(item.drawingNo && item.drawingNo.toLowerCase().includes(keyword)) ||
(item.createdBy && item.createdBy.toLowerCase().includes(keyword))
)
},
/** 处理生产令号变化 */
handleProductionOrderChange(selectedOrder) {
if (selectedOrder) {
this.productionObj = selectedOrder
this.mrpQueryParams.orderProId = selectedOrder.id
// MRP
this.getMrpData()
} else {
this.productionObj = null
this.mrpQueryParams.orderProId = null
this.mrpResultData = []
this.mrpTotal = 0
this.mrpStats = {
totalMaterials: 0,
positiveStock: 0,
negativeStock: 0,
zeroStock: 0
}
}
},
/** 查询MRP结果列表 */
getList() {
if (!this.productionObj) {
this.$message.warning('请先选择生产令号')
return
}
this.getMrpData()
},
/** 搜索按钮操作 */
handleQuery() {
this.mrpQueryParams.pageNum = 1
this.getList()
},
/** 重置按钮操作 */
resetQuery() {
this.resetForm("queryForm")
this.handleQuery()
},
/** 重置表单 */
resetForm(refName) {
if (this.$refs[refName]) {
this.$refs[refName].resetFields()
}
},
/** MRP运算结果复查相关方法 */
// MRP
async getMRPResults() {
if (!this.productionObj || !this.productionObj.id) {
this.$message.error('请先选择生产令号');
return;
}
//
this.$message({
message: '运算已开始,由于数据量较大,可能需要较长时间,请耐心等待...',
type: 'info',
duration: 6000, // 6
showClose: true
});
this.loadingMRP = true;
this.mrpOperationStatus = '运算已开始,正在处理数据...';
//
const progressTimer = setInterval(() => {
this.mrpOperationStatus = '运算仍在进行中,请继续等待...';
//
}, 30000);
try {
const response = await getMRPResults(this.productionObj.id);
//
clearInterval(progressTimer);
if (response && response.code === 200) {
this.$message.success('MRP运算完成');
// MRP
await this.getMrpData();
} else {
console.error('运算失败,响应:', response);
this.$message.error(response?.msg || '运算失败');
}
} catch (error) {
//
clearInterval(progressTimer);
console.error('运算异常:', error);
console.error('错误详情:', {
message: error.message,
code: error.code,
response: error.response,
status: error.response?.status,
data: error.response?.data
});
//
if (error.code === 'ECONNABORTED' || error.message.includes('timeout')) {
this.$message.error('运算超时,请稍后重试');
} else if (error.response?.status === 404) {
this.$message.error('运算接口不存在,请检查后端服务');
} else if (error.response?.status === 500) {
this.$message.error('运算服务器内部错误,请稍后重试');
} else {
this.$message.error(`运算失败: ${error.message || '未知错误'}`);
}
} finally {
this.loadingMRP = false;
this.mrpOperationStatus = ''; //
}
},
// MRP
async getMrpData() {
this.mrpLoading = true;
try {
this.mrpQueryParams.orderProId = this.productionObj.id;
const response = await listMrp(this.mrpQueryParams);
if (response && response.rows) {
// Number toFixed
const processedRows = response.rows.map(item => ({
...item,
availableStock: Number(item.availableStock) || 0,
realTimeStock: Number(item.realTimeStock) || 0,
prodNotInStock: Number(item.prodNotInStock) || 0,
purchaseRequestQty: Number(item.purchaseRequestQty) || 0,
purchaseNotInStock: Number(item.purchaseNotInStock) || 0,
childNotPickedQty: Number(item.childNotPickedQty) || 0,
createTime: item.createTime ? dayjs(item.createTime).format('YYYY-MM-DD HH:mm:ss') : '',
updateTime: item.updateTime ? dayjs(item.updateTime).format('YYYY-MM-DD HH:mm:ss') : ''
}));
this.mrpResultData = processedRows;
this.mrpTotal = response.total || processedRows.length;
//
this.calculateMrpStats(processedRows);
}
} catch (error) {
console.error('获取数据失败:', error);
this.$message.error('获取数据失败');
} finally {
this.mrpLoading = false;
}
},
// MRP
handleMrpSizeChange(size) {
this.mrpQueryParams.pageSize = size;
this.mrpQueryParams.pageNum = 1;
this.getMrpData();
},
// MRP
handleMrpCurrentChange(page) {
this.mrpQueryParams.pageNum = page;
this.getMrpData();
},
//
formatDateTime(date) {
if (!date) return '-';
if (typeof date === 'string') {
date = new Date(date);
}
if (isNaN(date.getTime())) return '-';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}`;
},
// MRP
handleMrpSearch() {
this.mrpQueryParams.pageNum = 1;
this.mrpQueryParams.materialCode = this.mrpSearchKeyword;
console.log('搜索参数:', this.mrpQueryParams);
this.getMrpData();
},
// MRP
clearMrpSearch() {
this.mrpSearchKeyword = '';
this.mrpQueryParams.materialCode = '';
this.mrpQueryParams.pageNum = 1;
this.getMrpData();
},
// MRP
filterMrpData(data) {
if (!this.mrpSearchKeyword) {
return data;
}
const keyword = this.mrpSearchKeyword.toLowerCase();
return data.filter(item =>
item.materialName.toLowerCase().includes(keyword) ||
item.materialCode.toLowerCase().includes(keyword)
);
},
// MRP
calculateMrpStats(data) {
const total = data.length;
const positive = data.filter(item => item.availableStock > 0).length;
const negative = data.filter(item => item.availableStock < 0).length;
const zero = data.filter(item => item.availableStock === 0).length;
this.mrpStats = {
totalMaterials: total,
positiveStock: positive,
negativeStock: negative,
zeroStock: zero
};
},
// MRP
handleRefreshMrpData() {
this.mrpQueryParams.pageNum = 1;
this.getMrpData();
},
// MRP
async handleExportMrp() {
//
if (!this.productionObj) {
this.$message.error('请先选择生产令号');
return;
}
if (!this.productionObj.id) {
this.$message.error('生产令号ID无效请重新选择');
return;
}
if (!this.productionObj.productionOrderNo) {
this.$message.error('生产令号信息不完整,请重新选择');
return;
}
//
console.log('productionObj:', this.productionObj);
console.log('productionObj.id:', this.productionObj.id);
console.log('mrpResultData.length:', this.mrpResultData?.length || 0);
//
const exportInfo = `导出生产令号"${this.productionObj.productionOrderNo}"的数据`;
const searchInfo = this.mrpSearchKeyword ? `,包含搜索关键词"${this.mrpSearchKeyword}"` : '';
const dataInfo = this.mrpResultData && this.mrpResultData.length > 0
? `,当前显示${this.mrpResultData.length}条记录`
: '(后台将查询所有相关数据)';
try {
await this.$confirm(
`${exportInfo}${searchInfo}${dataInfo}\n\n确定要导出吗`,
'确认导出',
{
confirmButtonText: '确定导出',
cancelButtonText: '取消',
type: 'info'
}
);
} catch (error) {
//
return;
}
this.exportLoading = true;
try {
// orderProId
const exportParams = {
orderProId: this.productionObj.id, // ID
materialCode: this.mrpSearchKeyword || '', //
materialName: '', //
pageSize: 9999, //
pageNum: 1
};
const response = await exportMrp(exportParams);
//
const blob = new Blob([response], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = `MRP运算结果_${this.productionObj.productionOrderNo}_${new Date().getTime()}.xlsx`;
link.click();
window.URL.revokeObjectURL(url);
this.$message.success(`导出成功文件已下载运算结果_${this.productionObj.productionOrderNo}_${new Date().getTime()}.xlsx`);
} catch (error) {
console.error('导出失败:', error);
this.$message.error('导出失败: ' + (error.message || error));
} finally {
this.exportLoading = false;
}
},
// MRP
getMrpRowClass({ row, rowIndex }) {
if (row.availableStock < 0) {
return 'negative-stock-row'
} else if (row.availableStock === 0) {
return 'zero-stock-row'
}
return ''
},
//
handleRefreshAll() {
this.getProductionOrderList()
if (this.productionObj) {
this.getMrpData()
}
},
//
goBack() {
if (window.history.length > 1) {
this.$router.go(-1)
} else {
//
this.$router.push('/')
}
}
}
}
</script>
<style scoped>
.mrp2-standalone-container {
min-height: 100vh;
background: #f5f5f5;
padding: 0;
}
.standalone-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 0;
margin-bottom: 20px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.header-content {
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left h1 {
color: white !important;
text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
}
.header-left p {
color: rgba(255, 255, 255, 0.8) !important;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
.header-right {
display: flex;
gap: 12px;
}
.page-content {
max-width: 1600px;
margin: 0 auto;
padding: 0 20px;
}
.app-container {
padding: 20px;
}
.page-header {
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #e4e7ed;
}
.mrp-result-card {
border: 1px solid #e4e7ed;
border-radius: 8px;
}
.mrp-status-indicator {
display: flex;
align-items: center;
padding: 8px 12px;
background: #f0f9ff;
border: 1px solid #b3d8ff;
border-radius: 4px;
color: #409eff;
font-size: 14px;
}
.mrp-calculate-btn {
background: linear-gradient(135deg, #409eff 0%, #66b1ff 100%);
border: none;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.mrp-calculate-btn:hover {
background: linear-gradient(135deg, #66b1ff 0%, #409eff 100%);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.4);
}
.mrp-search-input {
border-radius: 6px;
}
.mrp-export-btn {
background: linear-gradient(135deg, #67c23a 0%, #85ce61 100%);
border: none;
box-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
}
.mrp-export-btn:hover {
background: linear-gradient(135deg, #85ce61 0%, #67c23a 100%);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(103, 194, 58, 0.4);
}
/* 表格行样式 */
:deep(.negative-stock-row) {
background-color: #fef0f0 !important;
}
:deep(.negative-stock-row:hover > td) {
background-color: #fde2e2 !important;
}
:deep(.zero-stock-row) {
background-color: #fdf6ec !important;
}
:deep(.zero-stock-row:hover > td) {
background-color: #faecd8 !important;
}
/* 生产令号选择器优化样式 */
.production-order-select-dropdown {
min-width: 400px !important;
max-width: 600px !important;
max-height: 400px !important;
}
.production-order-select-dropdown .el-select-dropdown__item {
height: auto !important;
min-height: 40px !important;
padding: 8px 16px !important;
line-height: 1.4 !important;
white-space: normal !important;
overflow: visible !important;
border-bottom: 1px solid #f0f0f0 !important;
}
.production-order-select-dropdown .el-select-dropdown__item:last-child {
border-bottom: none !important;
}
.production-order-select-dropdown .el-select-dropdown__item:hover {
background-color: #f5f7fa !important;
}
.production-order-select-dropdown .el-select-dropdown__item.selected {
background-color: #ecf5ff !important;
color: #409eff !important;
}
.production-order-select-dropdown .el-select-dropdown__item.is-disabled {
color: #c0c4cc !important;
cursor: not-allowed !important;
}
/* 全局下拉选择器样式优化 */
:deep(.el-select-dropdown__item) {
height: auto !important;
padding: 12px 20px !important;
line-height: 1.4 !important;
white-space: normal !important;
}
:deep(.el-select-dropdown__item:hover) {
background-color: #f5f7fa !important;
}
:deep(.el-select-dropdown__item.selected) {
background-color: #ecf5ff !important;
color: #409eff !important;
}
/* 生产令号信息卡片样式 */
.production-order-info {
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-left: 4px solid #409eff;
}
.production-order-info .el-card__header {
background: linear-gradient(135deg, #f0f9ff 0%, #e0f2fe 100%);
border-bottom: 1px solid #b3d8ff;
}
/* 响应式设计 */
@media (max-width: 768px) {
.app-container {
padding: 10px;
}
.mrp-status-indicator {
font-size: 12px;
padding: 6px 8px;
}
.production-order-info .el-card__body {
padding: 15px;
}
}
</style>