Merge branch '0.8.X' of http://49.232.154.205:10100/DeXun/klp-oa into 0.8.X
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
<h3>{{ currentPlanSheetInfo.planSheetName || '排产单详情' }}</h3>
|
||||
<div>
|
||||
<el-button type="primary" plain @click="handleAdd">新增明细</el-button>
|
||||
<el-button type="success" plain @click="handleBatchAdd">批量新增</el-button>
|
||||
<el-button type="info" plain @click="getList">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -287,6 +288,75 @@
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 批量新增对话框 -->
|
||||
<el-dialog title="批量新增" :visible.sync="batchAddDialogVisible" width="80%" append-to-body>
|
||||
<div class="batch-add-content">
|
||||
<!-- 合同选择 -->
|
||||
<div class="contract-section">
|
||||
<div class="section-title">选择合同</div>
|
||||
<el-form :model="batchQueryParams" ref="batchQueryForm" size="small" :inline="true" label-width="80px">
|
||||
<el-form-item label="合同号" prop="contractCode">
|
||||
<el-input v-model="batchQueryParams.contractCode" placeholder="请输入合同号" style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="客户">
|
||||
<el-input v-model="batchQueryParams.customerName" placeholder="请输入客户名称" style="width: 180px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="业务员">
|
||||
<el-input v-model="batchQueryParams.salesman" placeholder="请输入业务员" style="width: 120px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="getBatchOrderList">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetBatchQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table v-loading="batchOrderLoading" :data="batchOrderList" style="width: 100%" border @row-click="selectBatchContract"
|
||||
highlight-current-row>
|
||||
<el-table-column prop="contractCode" label="合同号" />
|
||||
<el-table-column prop="signTime" label="签订时间" width="150" />
|
||||
<el-table-column prop="signLocation" label="签订地点" />
|
||||
<el-table-column prop="companyName" label="客户公司" />
|
||||
<el-table-column prop="salesman" label="业务员" width="100" />
|
||||
<el-table-column prop="deliveryDate" label="交货日期" width="150" />
|
||||
<el-table-column label="操作" width="80" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" size="small" @click.stop="selectBatchContract(scope.row)">选择</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination background layout="prev, pager, next, jumper" :total="batchOrderTotal"
|
||||
:page-size="batchQueryParams.pageSize" :current-page.sync="batchQueryParams.pageNum"
|
||||
@current-change="getBatchOrderList" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 明细选择 -->
|
||||
<div class="item-section" v-if="selectedContract">
|
||||
<div class="section-title">选择明细(多选)</div>
|
||||
<el-table v-loading="batchItemLoading" :data="batchItemList" style="width: 100%" border
|
||||
@selection-change="handleBatchItemSelectionChange">
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="产品类型" align="center" prop="productType" />
|
||||
<el-table-column label="成品宽度" align="center" prop="width" />
|
||||
<el-table-column label="成品厚度" align="center" prop="thickness" />
|
||||
<el-table-column label="成品规格" align="center" prop="finishedProductSpec" />
|
||||
<el-table-column label="材质" align="center" prop="material" />
|
||||
<el-table-column label="重量" align="center" prop="weight" />
|
||||
<el-table-column label="卷数" align="center" prop="productNum" />
|
||||
<el-table-column label="表面处理" align="center" prop="surfaceTreatment" />
|
||||
<el-table-column label="包装要求" align="center" prop="packagingReq" />
|
||||
<el-table-column label="切边要求" align="center" prop="edgeCuttingReq" />
|
||||
<el-table-column label="用途" align="center" prop="purpose" />
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="batchAddDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmBatchAdd" :disabled="selectedBatchItems.length === 0">确认新增</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -351,7 +421,31 @@ export default {
|
||||
// 订单明细加载状态
|
||||
orderItemLoading: false,
|
||||
// 当前编辑的行
|
||||
currentEditingRow: null
|
||||
currentEditingRow: null,
|
||||
// 批量新增对话框
|
||||
batchAddDialogVisible: false,
|
||||
// 批量查询参数
|
||||
batchQueryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
contractCode: undefined,
|
||||
customerName: undefined,
|
||||
salesman: undefined
|
||||
},
|
||||
// 批量订单列表
|
||||
batchOrderList: [],
|
||||
// 批量订单总数
|
||||
batchOrderTotal: 0,
|
||||
// 批量订单加载状态
|
||||
batchOrderLoading: false,
|
||||
// 批量明细列表
|
||||
batchItemList: [],
|
||||
// 批量明细加载状态
|
||||
batchItemLoading: false,
|
||||
// 选中的合同
|
||||
selectedContract: null,
|
||||
// 选中的明细
|
||||
selectedBatchItems: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
@@ -582,6 +676,98 @@ export default {
|
||||
// 处理订单行点击
|
||||
handleOrderSelect(row) {
|
||||
this.selectOrder(row);
|
||||
},
|
||||
// 打开批量新增对话框
|
||||
handleBatchAdd() {
|
||||
this.batchAddDialogVisible = true;
|
||||
this.selectedContract = null;
|
||||
this.selectedBatchItems = [];
|
||||
this.getBatchOrderList();
|
||||
},
|
||||
// 获取批量订单列表
|
||||
getBatchOrderList() {
|
||||
this.batchOrderLoading = true;
|
||||
listOrder(this.batchQueryParams).then(response => {
|
||||
this.batchOrderList = response.rows;
|
||||
this.batchOrderTotal = response.total;
|
||||
this.batchOrderLoading = false;
|
||||
});
|
||||
},
|
||||
// 重置批量查询参数
|
||||
resetBatchQuery() {
|
||||
this.batchQueryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
contractCode: undefined,
|
||||
customerName: undefined,
|
||||
salesman: undefined
|
||||
};
|
||||
this.getBatchOrderList();
|
||||
},
|
||||
// 选择批量合同
|
||||
selectBatchContract(row) {
|
||||
this.selectedContract = row;
|
||||
this.selectedBatchItems = [];
|
||||
this.batchItemLoading = true;
|
||||
listOrderItem({ orderId: row.orderId }).then(res => {
|
||||
this.batchItemList = res.rows;
|
||||
this.batchItemLoading = false;
|
||||
});
|
||||
},
|
||||
// 处理批量明细选择变更
|
||||
handleBatchItemSelectionChange(selection) {
|
||||
this.selectedBatchItems = selection;
|
||||
},
|
||||
// 确认批量新增
|
||||
confirmBatchAdd() {
|
||||
if (this.selectedBatchItems.length === 0) {
|
||||
this.$message.warning('请至少选择一条明细');
|
||||
return;
|
||||
}
|
||||
|
||||
this.$confirm(`确认新增 ${this.selectedBatchItems.length} 条明细?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const currentMaxSeqNo = this.planDetailList.length > 0
|
||||
? Math.max(...this.planDetailList.map(item => parseInt(item.bizSeqNo) || 0))
|
||||
: 0;
|
||||
|
||||
const addPromises = this.selectedBatchItems.map((item, index) => {
|
||||
const newRow = {
|
||||
planSheetId: this.currentPlanSheetId,
|
||||
bizSeqNo: currentMaxSeqNo + index + 1,
|
||||
orderCode: this.selectedContract.orderCode,
|
||||
contractCode: this.selectedContract.contractCode,
|
||||
customerName: this.selectedContract.companyName,
|
||||
salesman: this.selectedContract.salesman,
|
||||
orderId: this.selectedContract.orderId,
|
||||
productName: item.productType,
|
||||
productMaterial: item.material,
|
||||
productWidth: item.width,
|
||||
rollingThick: item.thickness,
|
||||
markCoatThick: item.thickness,
|
||||
tonSteelLengthRange: 0,
|
||||
planQty: item.productNum,
|
||||
planWeight: item.weight,
|
||||
surfaceTreatment: item.surfaceTreatment,
|
||||
productPackaging: item.packagingReq,
|
||||
widthReq: item.edgeCuttingReq,
|
||||
productEdgeReq: item.widthTolerance,
|
||||
usageReq: item.purpose
|
||||
};
|
||||
return addPlanDetail(newRow);
|
||||
});
|
||||
|
||||
Promise.all(addPromises).then(() => {
|
||||
this.$message.success('批量新增成功');
|
||||
this.batchAddDialogVisible = false;
|
||||
this.getList();
|
||||
}).catch(error => {
|
||||
this.$message.error('批量新增失败');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -654,4 +840,25 @@ export default {
|
||||
/* ::v-deep .el-input__inner {
|
||||
padding: 0 1px;
|
||||
} */
|
||||
|
||||
.batch-add-content {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.contract-section {
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.item-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 15px;
|
||||
color: #303133;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -42,6 +42,16 @@
|
||||
<el-tag v-else-if="scope.row.objectionStatus === 2" type="info">已关闭</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="钢卷信息" align="center" prop="coilList" width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.coilList && scope.row.coilList.length > 0">
|
||||
<div v-for="(coil, index) in scope.row.coilList" :key="coil.coilId || index" style="margin-bottom: 4px;">
|
||||
<CurrentCoilNo @click.native="handleClickCoil(coil)" :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="处理结果" align="center" prop="handleContent" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<div class="cell-html" v-html="scope.row.handleContent"></div>
|
||||
@@ -53,11 +63,6 @@
|
||||
<span>{{ parseTime(scope.row.handleTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="结案时间" align="center" prop="closeTime" width="180">
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.closeTime, '{y}-{m}-{d}') }}</span>
|
||||
</template>
|
||||
</el-table-column> -->
|
||||
<el-table-column label="备注" align="center" prop="remark" />
|
||||
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
|
||||
<template slot-scope="scope">
|
||||
@@ -66,12 +71,6 @@
|
||||
v-if="scope.row.objectionStatus == 0"></el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-view" @click="handleView(scope.row)"
|
||||
v-if="scope.row.objectionStatus == 1"></el-button>
|
||||
<!-- <el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-check"
|
||||
@click="handleFinish(scope.row)"
|
||||
>结案</el-button> -->
|
||||
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -113,28 +112,28 @@
|
||||
placeholder="请输入客户诉求"
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="处理内容">
|
||||
<editor v-model="form.handleContent" :min-height="192"/>
|
||||
<el-form-item label="关联钢卷">
|
||||
<div style="width: 100%;">
|
||||
<CoilSelector
|
||||
:multiple="true"
|
||||
:rangeMode="true"
|
||||
:rangeData="shippedCoils"
|
||||
:orderBy="true"
|
||||
@confirm="(coils) => handleCoilConfirm('form', coils)"
|
||||
placeholder="选择钢卷">
|
||||
<el-button type="primary" size="small">
|
||||
<i class="el-icon-search"></i> 选择钢卷
|
||||
</el-button>
|
||||
</CoilSelector>
|
||||
<div v-if="formCoilList.length > 0" style="margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px;">
|
||||
<div v-for="(coil, index) in formCoilList" :key="coil.coilId || index" style="display: flex; align-items: center; gap: 4px;">
|
||||
<CurrentCoilNo :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
<el-button type="text" icon="el-icon-close" size="mini" @click="removeCoil('form', index)"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span v-else style="color: #909399; font-size: 12px;">暂未选择钢卷</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item label="处理人" prop="handleUser">
|
||||
<el-input v-model="form.handleUser" placeholder="请输入处理人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="处理时间" prop="handleTime">
|
||||
<el-date-picker clearable
|
||||
v-model="form.handleTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择处理时间">
|
||||
</el-date-picker>
|
||||
</el-form-item>
|
||||
<el-form-item label="结案时间" prop="closeTime">
|
||||
<el-date-picker clearable
|
||||
v-model="form.closeTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择结案时间">
|
||||
</el-date-picker>
|
||||
</el-form-item> -->
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" placeholder="请输入备注" />
|
||||
</el-form-item>
|
||||
@@ -150,17 +149,6 @@
|
||||
<el-form-item label="处理内容">
|
||||
<editor v-model="checkForm.handleContent" :min-height="192" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="处理人" prop="handleUser">
|
||||
<el-input v-model="form.handleUser" placeholder="请输入处理人" />
|
||||
</el-form-item>
|
||||
<el-form-item label="处理时间" prop="handleTime">
|
||||
<el-date-picker clearable
|
||||
v-model="form.handleTime"
|
||||
type="datetime"
|
||||
value-format="yyyy-MM-dd HH:mm:ss"
|
||||
placeholder="请选择处理时间">
|
||||
</el-date-picker>
|
||||
</el-form-item> -->
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button :loading="buttonLoading" type="primary" @click="submitCheckForm">确 定</el-button>
|
||||
@@ -180,6 +168,14 @@
|
||||
<el-descriptions-item label="处理内容" :span="2">
|
||||
<div v-html="viewForm.handleContent"></div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="关联钢卷" :span="2">
|
||||
<div v-if="viewForm.coilList && viewForm.coilList.length > 0" style="display: flex; flex-wrap: wrap; gap: 8px;">
|
||||
<div v-for="(coil, index) in viewForm.coilList" :key="coil.coilId || index">
|
||||
<CurrentCoilNo @click.native="handleClickCoil(coil)" :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="viewOpen = false">关 闭</el-button>
|
||||
@@ -190,9 +186,16 @@
|
||||
|
||||
<script>
|
||||
import { listSalesObjection, getSalesObjection, delSalesObjection, addSalesObjection, updateSalesObjection } from "@/api/crm/salesObjection";
|
||||
import { listOrderPackaging } from "@/api/crm/order";
|
||||
import CoilSelector from "@/components/CoilSelector/index.vue";
|
||||
import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue";
|
||||
|
||||
export default {
|
||||
name: "SalesObjection",
|
||||
components: {
|
||||
CoilSelector,
|
||||
CurrentCoilNo
|
||||
},
|
||||
props: {
|
||||
order: {
|
||||
type: Object,
|
||||
@@ -273,6 +276,11 @@ export default {
|
||||
checkOpen: false,
|
||||
viewForm: {},
|
||||
viewOpen: false,
|
||||
// 钢卷选择相关
|
||||
coilSelectorType: 'form', // form 或 check
|
||||
formCoilList: [], // 表单中的钢卷列表
|
||||
checkCoilList: [], // 处理中的钢卷列表
|
||||
shippedCoils: [], // 订单已发货的钢卷(可选范围)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -290,9 +298,11 @@ export default {
|
||||
this.open = false;
|
||||
this.reset();
|
||||
},
|
||||
handleView(row) {
|
||||
this.viewForm = row;
|
||||
this.viewOpen = true;
|
||||
// 点击钢卷
|
||||
handleClickCoil(coil) {
|
||||
this.$router.push({
|
||||
path: '/wms/coil/' + coil.coilId,
|
||||
});
|
||||
},
|
||||
// 表单重置
|
||||
reset() {
|
||||
@@ -335,70 +345,6 @@ export default {
|
||||
this.single = selection.length !== 1
|
||||
this.multiple = !selection.length
|
||||
},
|
||||
handleDo(row) {
|
||||
console.log(row, '处理')
|
||||
this.checkForm = row;
|
||||
this.checkOpen = true;
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.open = true;
|
||||
this.title = "添加销售异议管理";
|
||||
},
|
||||
/** 修改按钮操作 */
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
const objectionId = row.objectionId || this.ids
|
||||
getSalesObjection(objectionId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
this.open = true;
|
||||
this.title = "修改销售异议管理";
|
||||
});
|
||||
},
|
||||
/** 提交按钮 */
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
if (this.form.objectionId != null) {
|
||||
updateSalesObjection(this.form).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addSalesObjection(this.form).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
/** 提交处理按钮 */
|
||||
submitCheckForm() {
|
||||
this.buttonLoading = true;
|
||||
updateSalesObjection({
|
||||
...this.checkForm,
|
||||
handleUser: this.currentUserName,
|
||||
handleTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}'),
|
||||
objectionStatus: 1,
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess("处理成功");
|
||||
this.checkOpen = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
},
|
||||
/** 删除按钮操作 */
|
||||
handleDelete(row) {
|
||||
const objectionIds = row.objectionId || this.ids;
|
||||
@@ -419,6 +365,137 @@ export default {
|
||||
this.download('crm/salesObjection/export', {
|
||||
...this.queryParams
|
||||
}, `salesObjection_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
|
||||
// ==================== 钢卷相关方法 ====================
|
||||
// 获取订单已发货的钢卷
|
||||
getShippedCoils() {
|
||||
if (this.orderId) {
|
||||
listOrderPackaging(this.orderId).then(response => {
|
||||
this.shippedCoils = response.data || [];
|
||||
}).catch(() => {
|
||||
this.shippedCoils = [];
|
||||
});
|
||||
} else {
|
||||
this.shippedCoils = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 钢卷选择确认
|
||||
handleCoilConfirm(type, selectedCoils) {
|
||||
if (type === 'form') {
|
||||
this.formCoilList = [...selectedCoils];
|
||||
} else if (type === 'check') {
|
||||
this.checkCoilList = [...selectedCoils];
|
||||
}
|
||||
},
|
||||
|
||||
// 移除选中的钢卷
|
||||
removeCoil(type, index) {
|
||||
if (type === 'form') {
|
||||
this.formCoilList.splice(index, 1);
|
||||
} else if (type === 'check') {
|
||||
this.checkCoilList.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
// 将钢卷数组转换为CSV字符串
|
||||
coilListToCsv(coilList) {
|
||||
if (!coilList || coilList.length === 0) {
|
||||
return '';
|
||||
}
|
||||
return coilList.map(coil => coil.coilId).join(',');
|
||||
},
|
||||
|
||||
// 从coilIds CSV和coilList中恢复钢卷数据
|
||||
// 重写handleAdd方法
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.formCoilList = []; // 清空钢卷列表
|
||||
this.getShippedCoils(); // 获取可选择的钢卷
|
||||
this.open = true;
|
||||
this.title = "添加销售异议管理";
|
||||
},
|
||||
|
||||
// 重写handleUpdate方法
|
||||
handleUpdate(row) {
|
||||
this.loading = true;
|
||||
this.reset();
|
||||
this.getShippedCoils(); // 获取可选择的钢卷
|
||||
const objectionId = row.objectionId || this.ids;
|
||||
getSalesObjection(objectionId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
// 恢复钢卷列表
|
||||
this.formCoilList = response.data.coilList || [];
|
||||
this.open = true;
|
||||
this.title = "修改销售异议管理";
|
||||
});
|
||||
},
|
||||
|
||||
// 重写handleDo方法
|
||||
handleDo(row) {
|
||||
console.log(row, '处理');
|
||||
this.checkForm = row;
|
||||
this.checkCoilList = row.coilList || []; // 恢复钢卷列表
|
||||
this.getShippedCoils(); // 获取可选择的钢卷
|
||||
this.checkOpen = true;
|
||||
},
|
||||
|
||||
// 重写handleView方法
|
||||
handleView(row) {
|
||||
this.viewForm = row;
|
||||
this.viewOpen = true;
|
||||
},
|
||||
|
||||
// 重写submitForm方法,添加coilIds
|
||||
submitForm() {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
// 添加coilIds
|
||||
const formData = {
|
||||
...this.form,
|
||||
coilIds: this.coilListToCsv(this.formCoilList)
|
||||
};
|
||||
|
||||
if (this.form.objectionId != null) {
|
||||
updateSalesObjection(formData).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addSalesObjection(formData).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 重写submitCheckForm方法,添加coilIds
|
||||
submitCheckForm() {
|
||||
this.buttonLoading = true;
|
||||
updateSalesObjection({
|
||||
...this.checkForm,
|
||||
handleUser: this.currentUserName,
|
||||
handleTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}'),
|
||||
objectionStatus: 1,
|
||||
coilIds: this.coilListToCsv(this.checkCoilList)
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess("处理成功");
|
||||
this.checkOpen = false;
|
||||
this.getList();
|
||||
}).finally(() => {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,6 +42,16 @@
|
||||
<el-tag v-else-if="scope.row.objectionStatus === 2" type="info">已关闭</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="钢卷信息" align="center" prop="coilList" width="200" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<div v-if="scope.row.coilList && scope.row.coilList.length > 0">
|
||||
<div v-for="(coil, index) in scope.row.coilList" :key="coil.coilId || index" style="margin-bottom: 4px;">
|
||||
<CurrentCoilNo @click.native="handleClickCoil(coil)" :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<!-- <el-table-column label="处理内容" align="center" prop="handleContent" /> -->
|
||||
<el-table-column label="处理人" align="center" prop="handleUser" />
|
||||
<el-table-column label="处理时间" align="center" prop="handleTime" width="180">
|
||||
@@ -110,7 +120,29 @@
|
||||
></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="订单编号">
|
||||
<order-select v-model="form.orderId" placeholder="请选择订单" />
|
||||
<order-select v-model="form.orderId" placeholder="请选择订单" @change="getShippedCoils" />
|
||||
</el-form-item>
|
||||
<el-form-item label="关联钢卷">
|
||||
<div style="width: 100%;">
|
||||
<CoilSelector
|
||||
:multiple="true"
|
||||
:rangeMode="true"
|
||||
:rangeData="shippedCoils"
|
||||
:orderBy="true"
|
||||
@confirm="(coils) => handleCoilConfirm('form', coils)"
|
||||
placeholder="选择钢卷">
|
||||
<el-button type="primary" size="small">
|
||||
<i class="el-icon-search"></i> 选择钢卷
|
||||
</el-button>
|
||||
</CoilSelector>
|
||||
<div v-if="formCoilList.length > 0" style="margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px;">
|
||||
<div v-for="(coil, index) in formCoilList" :key="coil.coilId || index" style="display: flex; align-items: center; gap: 4px;">
|
||||
<CurrentCoilNo :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
<el-button type="text" icon="el-icon-close" size="mini" @click="removeCoil('form', index)"></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<span v-else style="color: #909399; font-size: 12px;">暂未选择钢卷</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="处理内容">
|
||||
<editor v-model="form.handleContent" :min-height="192"/>
|
||||
@@ -163,6 +195,14 @@
|
||||
<el-descriptions-item label="反馈日期">{{ parseTime(viewForm.returnDate, '{y}-{m}-{d}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="投诉情况" :span="2">{{ viewForm.complaintContent }}</el-descriptions-item>
|
||||
<el-descriptions-item label="客户诉求" :span="2">{{ viewForm.customerDemand }}</el-descriptions-item>
|
||||
<el-descriptions-item label="关联钢卷" :span="2">
|
||||
<div v-if="viewForm.coilList && viewForm.coilList.length > 0" style="display: flex; flex-wrap: wrap; gap: 8px;">
|
||||
<div v-for="(coil, index) in viewForm.coilList" :key="coil.coilId || index">
|
||||
<CurrentCoilNo @click.native="handleClickCoil(coil)" :currentCoilNo="coil.currentCoilNo || coil.coilNo || ''" />
|
||||
</div>
|
||||
</div>
|
||||
<span v-else>-</span>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="处理人">{{ viewForm.handleUser }}</el-descriptions-item>
|
||||
<el-descriptions-item label="处理时间">{{ parseTime(viewForm.handleTime, '{y}-{m}-{d}') }}</el-descriptions-item>
|
||||
<el-descriptions-item label="处理内容" :span="2">
|
||||
@@ -178,14 +218,19 @@
|
||||
|
||||
<script>
|
||||
import { listSalesObjection, getSalesObjection, delSalesObjection, addSalesObjection, updateSalesObjection } from "@/api/crm/salesObjection";
|
||||
import { listOrderPackaging } from "@/api/crm/order";
|
||||
import OrderSelect from "@/components/KLPService/OrderSelect";
|
||||
import CustomerSelect from "@/components/KLPService/CustomerSelect";
|
||||
import CoilSelector from "@/components/CoilSelector/index.vue";
|
||||
import CurrentCoilNo from "@/components/KLPService/Renderer/CurrentCoilNo.vue";
|
||||
|
||||
export default {
|
||||
name: "SalesObjection",
|
||||
components: {
|
||||
OrderSelect,
|
||||
CustomerSelect,
|
||||
CoilSelector,
|
||||
CurrentCoilNo
|
||||
},
|
||||
computed: {
|
||||
currentUserName() {
|
||||
@@ -245,6 +290,11 @@ export default {
|
||||
checkOpen: false,
|
||||
viewForm: {},
|
||||
viewOpen: false,
|
||||
// 钢卷选择相关
|
||||
coilSelectorType: 'form', // form 或 check
|
||||
formCoilList: [], // 表单中的钢卷列表
|
||||
checkCoilList: [], // 处理中的钢卷列表
|
||||
shippedCoils: [], // 订单已发货的钢卷(可选范围)
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
@@ -271,7 +321,7 @@ export default {
|
||||
this.form = {
|
||||
objectionId: undefined,
|
||||
objectionCode: undefined,
|
||||
orderId: this.orderId,
|
||||
orderId: undefined,
|
||||
productCategory: undefined,
|
||||
returnDate: undefined,
|
||||
complaintContent: undefined,
|
||||
@@ -310,11 +360,13 @@ export default {
|
||||
handleDo(row) {
|
||||
console.log(row, '处理')
|
||||
this.checkForm = row;
|
||||
this.checkCoilList = row.coilList || []; // 恢复钢卷列表
|
||||
this.checkOpen = true;
|
||||
},
|
||||
/** 新增按钮操作 */
|
||||
handleAdd() {
|
||||
this.reset();
|
||||
this.formCoilList = []; // 清空钢卷列表
|
||||
this.open = true;
|
||||
this.title = "添加销售异议管理";
|
||||
},
|
||||
@@ -326,6 +378,12 @@ export default {
|
||||
getSalesObjection(objectionId).then(response => {
|
||||
this.loading = false;
|
||||
this.form = response.data;
|
||||
// 恢复钢卷列表
|
||||
this.formCoilList = response.data.coilList || [];
|
||||
// 获取可选择的钢卷
|
||||
if (this.form.orderId) {
|
||||
this.getShippedCoils();
|
||||
}
|
||||
this.open = true;
|
||||
this.title = "修改销售异议管理";
|
||||
});
|
||||
@@ -335,8 +393,14 @@ export default {
|
||||
this.$refs["form"].validate(valid => {
|
||||
if (valid) {
|
||||
this.buttonLoading = true;
|
||||
// 添加coilIds
|
||||
const formData = {
|
||||
...this.form,
|
||||
coilIds: this.coilListToCsv(this.formCoilList)
|
||||
};
|
||||
|
||||
if (this.form.objectionId != null) {
|
||||
updateSalesObjection(this.form).then(response => {
|
||||
updateSalesObjection(formData).then(response => {
|
||||
this.$modal.msgSuccess("修改成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
@@ -344,7 +408,7 @@ export default {
|
||||
this.buttonLoading = false;
|
||||
});
|
||||
} else {
|
||||
addSalesObjection(this.form).then(response => {
|
||||
addSalesObjection(formData).then(response => {
|
||||
this.$modal.msgSuccess("新增成功");
|
||||
this.open = false;
|
||||
this.getList();
|
||||
@@ -363,6 +427,7 @@ export default {
|
||||
handleUser: this.currentUserName,
|
||||
handleTime: this.parseTime(new Date(), '{y}-{m}-{d} {h}:{i}:{s}'),
|
||||
objectionStatus: 1,
|
||||
coilIds: this.coilListToCsv(this.checkCoilList)
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess("处理成功");
|
||||
this.checkOpen = false;
|
||||
@@ -391,6 +456,53 @@ export default {
|
||||
this.download('crm/salesObjection/export', {
|
||||
...this.queryParams
|
||||
}, `salesObjection_${new Date().getTime()}.xlsx`)
|
||||
},
|
||||
|
||||
// ==================== 钢卷相关方法 ====================
|
||||
// 点击钢卷
|
||||
handleClickCoil(coil) {
|
||||
this.$router.push({
|
||||
path: '/wms/coil/' + coil.coilId,
|
||||
});
|
||||
},
|
||||
|
||||
// 获取订单已发货的钢卷
|
||||
getShippedCoils() {
|
||||
if (this.form.orderId) {
|
||||
listOrderPackaging(this.form.orderId).then(response => {
|
||||
this.shippedCoils = response.data || [];
|
||||
}).catch(() => {
|
||||
this.shippedCoils = [];
|
||||
});
|
||||
} else {
|
||||
this.shippedCoils = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 钢卷选择确认
|
||||
handleCoilConfirm(type, selectedCoils) {
|
||||
if (type === 'form') {
|
||||
this.formCoilList = [...selectedCoils];
|
||||
} else if (type === 'check') {
|
||||
this.checkCoilList = [...selectedCoils];
|
||||
}
|
||||
},
|
||||
|
||||
// 移除选中的钢卷
|
||||
removeCoil(type, index) {
|
||||
if (type === 'form') {
|
||||
this.formCoilList.splice(index, 1);
|
||||
} else if (type === 'check') {
|
||||
this.checkCoilList.splice(index, 1);
|
||||
}
|
||||
},
|
||||
|
||||
// 将钢卷数组转换为CSV字符串
|
||||
coilListToCsv(coilList) {
|
||||
if (!coilList || coilList.length === 0) {
|
||||
return '';
|
||||
}
|
||||
return coilList.map(coil => coil.coilId).join(',');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,960 @@
|
||||
<template>
|
||||
<div class="actual-container">
|
||||
<!-- 顶部实绩列表 (PLTCM_PDO_EXCOIL) -->
|
||||
<div class="top-section">
|
||||
<el-table
|
||||
ref="excoilTable"
|
||||
:data="excoilRows"
|
||||
size="mini"
|
||||
highlight-current-row
|
||||
border
|
||||
:height="topTableHeight"
|
||||
style="width:100%"
|
||||
@row-click="handleRowClick"
|
||||
>
|
||||
<el-table-column label="子卷号" min-width="110" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.EXCOILID || row.excoilid }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="热卷号" min-width="100" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.HOT_COILID || row.hot_coilid || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="班" width="40" align="center">
|
||||
<template slot-scope="{ row }">{{ row.SHIFT || row.shift || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="组" width="40" align="center">
|
||||
<template slot-scope="{ row }">{{ row.CREW || row.crew || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="钢种" min-width="80" show-overflow-tooltip>
|
||||
<template slot-scope="{ row }">{{ row.ORDER_QUALITY || row.order_quality || row.GRADE || row.grade || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料厚度" width="68" align="right">
|
||||
<template slot-scope="{ row }">{{ row.ENTRY_THICK || row.entry_thick || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口厚度" width="68" align="right">
|
||||
<template slot-scope="{ row }">{{ row.EXIT_THICK || row.exit_thick || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="偏差上限" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.EXIT_POS_DEV || row.exit_pos_dev || '0' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="偏差下限" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.EXIT_NEG_DEV || row.exit_neg_dev || '0' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料宽度" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.ENTRY_WIDTH || row.entry_width || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="出口宽度" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.EXIT_WIDTH || row.exit_width || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="来料重量" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.USED_ENTRY_WEIGHT || row.used_entry_weight || row.ENTRY_WEIGHT || row.entry_weight || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="称重重量" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.MEAS_EXIT_WEIGHT || row.meas_exit_weight || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="包装要求" width="60">
|
||||
<template slot-scope="{ row }">{{ row.PARK_TYPE || row.park_type || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="切边要求" width="60">
|
||||
<template slot-scope="{ row }">{{ row.SIDE_TRIM || row.side_trim || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成品质量" width="58" align="right">
|
||||
<template slot-scope="{ row }">{{ row.QUALITY || row.quality || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="成品长度" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ row.EXIT_LENGTH || row.exit_length || '—' }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="吨钢长度" width="60" align="right">
|
||||
<template slot-scope="{ row }">{{ calcLengthPerTon(row) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="下线时间" width="140">
|
||||
<template slot-scope="{ row }">{{ formatDate(row.END_DATE || row.end_date) }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="68" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-tag type="primary" size="mini" effect="plain">{{ row.STATUS || row.status || '产出' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div class="table-pagination">
|
||||
<el-pagination
|
||||
small layout="total, prev, pager, next"
|
||||
:total="pagination.total"
|
||||
:page-size="pagination.pageSize"
|
||||
:current-page="pagination.page"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部图表区域 -->
|
||||
<div class="bottom-section">
|
||||
<div class="chart-section">
|
||||
<el-tabs v-model="activeTab" size="small" class="chart-tabs" @tab-click="handleTabSwitch">
|
||||
|
||||
<!-- ① 趋势参数:左树形目录 + 右单图 -->
|
||||
<el-tab-pane label="趋势参数" name="trend">
|
||||
<div v-if="!selectedRow" class="no-data-hint">请在上方选择钢卷</div>
|
||||
<div v-else-if="segLoading" class="no-data-hint">加载中…</div>
|
||||
<div v-else-if="!segData" class="no-data-hint">暂无 SEG 数据</div>
|
||||
<div v-else class="trend-layout">
|
||||
<!-- 左侧目录树 -->
|
||||
<div class="trend-tree">
|
||||
<div v-for="group in trendGroups" :key="group.label" class="tree-group">
|
||||
<div class="tree-group-label" @click="toggleGroup(group.label)">
|
||||
<i :class="expandedGroups[group.label] ? 'el-icon-caret-bottom' : 'el-icon-caret-right'" />
|
||||
{{ group.label }}
|
||||
</div>
|
||||
<div v-show="expandedGroups[group.label]" class="tree-children">
|
||||
<div
|
||||
v-for="item in group.children"
|
||||
:key="item.col"
|
||||
class="tree-item"
|
||||
:class="{ active: selectedTrendParam && selectedTrendParam.col === item.col }"
|
||||
@click="selectTrendParam(item)"
|
||||
>{{ item.label }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 右侧图表 -->
|
||||
<div class="trend-chart-area">
|
||||
<div v-if="!selectedTrendParam" class="no-data-hint">← 点击左侧参数查看曲线</div>
|
||||
<!-- 保持 DOM 存在,仅用 v-show 控制显示,避免 ref 失效 -->
|
||||
<div ref="trendSingleChart" :style="{ display: selectedTrendParam ? 'block' : 'none', height: '100%', width: '100%' }" />
|
||||
</div>
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ② 厚度曲线 -->
|
||||
<el-tab-pane label="厚度曲线" name="thickness">
|
||||
<div v-if="!selectedRow" class="no-data-hint">请在上方选择钢卷</div>
|
||||
<div v-else-if="realtimeLoading" class="no-data-hint">加载中…</div>
|
||||
<div v-else-if="!gaugeRows || !gaugeRows.length" class="no-data-hint">暂无厚度数据</div>
|
||||
<div v-else class="charts-scroll charts-grid">
|
||||
<div ref="chartGauge1" class="chart-box" />
|
||||
<div ref="chartGauge2" class="chart-box" />
|
||||
<div ref="chartGauge3" class="chart-box" />
|
||||
<div ref="chartGauge4" class="chart-box" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ③ 带钢板形 热力图 -->
|
||||
<el-tab-pane label="带钢板形" name="flatness3d">
|
||||
<div v-if="!selectedRow" class="no-data-hint">请在上方选择钢卷</div>
|
||||
<div v-else-if="realtimeLoading" class="no-data-hint">加载中…</div>
|
||||
<div v-else-if="!shapeRows || !shapeRows.length" class="no-data-hint">暂无板形数据</div>
|
||||
<div v-else class="charts-scroll">
|
||||
<div ref="chartFlatness3d" class="chart-box chart-box-tall" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- ④ 板形曲线:一行两图 -->
|
||||
<el-tab-pane label="板形曲线" name="flatness">
|
||||
<div v-if="!selectedRow" class="no-data-hint">请在上方选择钢卷</div>
|
||||
<div v-else-if="realtimeLoading" class="no-data-hint">加载中…</div>
|
||||
<div v-else-if="!shapeRows || !shapeRows.length" class="no-data-hint">暂无板形数据</div>
|
||||
<div v-else class="charts-scroll charts-grid">
|
||||
<div ref="chartFlatDev" class="chart-box" />
|
||||
<div ref="chartTilt" class="chart-box" />
|
||||
<div ref="chartWrBend" class="chart-box" />
|
||||
<div ref="chartIrBend" class="chart-box" />
|
||||
</div>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</div>
|
||||
|
||||
<!-- 右侧查找面板 -->
|
||||
<div class="search-panel">
|
||||
<div class="panel-title">查找</div>
|
||||
<div class="search-type-group">
|
||||
<el-radio v-model="searchType" label="coil">按钢卷号</el-radio>
|
||||
<div v-if="searchType === 'coil'" class="search-field">
|
||||
<span class="search-label">钢卷号:</span>
|
||||
<el-input v-model="searchCoilId" size="mini" style="width:140px" placeholder="EXCOILID" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-type-group">
|
||||
<el-radio v-model="searchType" label="time">按时间</el-radio>
|
||||
<template v-if="searchType === 'time'">
|
||||
<div class="search-field">
|
||||
<span class="search-label">开始时间:</span>
|
||||
<el-date-picker v-model="searchStartDate" type="datetime" size="mini" style="width:160px"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="开始时间" />
|
||||
</div>
|
||||
<div class="search-field">
|
||||
<span class="search-label">结束时间:</span>
|
||||
<el-date-picker v-model="searchEndDate" type="datetime" size="mini" style="width:160px"
|
||||
value-format="yyyy-MM-dd HH:mm:ss" placeholder="结束时间" />
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="search-actions">
|
||||
<el-button type="primary" size="mini" :loading="excoilLoading" @click="handleFindSearch">查找</el-button>
|
||||
<el-button size="mini" @click="handleFindReset">重置</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import * as echarts from 'echarts'
|
||||
import 'echarts-gl'
|
||||
import {
|
||||
getExcoilList,
|
||||
getExcoilCount,
|
||||
getTimingSegByEncoilId,
|
||||
getTimingRealtimeData
|
||||
} from '@/api/l2/timing'
|
||||
|
||||
// 趋势参数树结构,对应 PLTCM_PRO_SEG 列名
|
||||
const TREND_GROUPS = [
|
||||
{
|
||||
label: '张力',
|
||||
children: [
|
||||
{ label: '开卷张力', col: 'PORTENS' },
|
||||
{ label: '入口活套张力', col: 'ENLTENS' },
|
||||
{ label: '拉矫张力', col: 'TLTENS' },
|
||||
{ label: '酸洗张力', col: 'PLTENS' },
|
||||
{ label: '出口活套张力', col: 'CXLTENS' },
|
||||
{ label: '圆盘剪张力', col: 'TRIMTENS' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '速度',
|
||||
children: [
|
||||
{ label: '开卷速度', col: 'PORSPEED' },
|
||||
{ label: '酸洗速度', col: 'PLSPEED' },
|
||||
{ label: '圆盘剪速度', col: 'TRIMSPEED' },
|
||||
{ label: '轧机入口速度', col: 'MILLENTRYSPEED' },
|
||||
{ label: '轧机出口速度', col: 'MILLEXITSPEED' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '拉矫机',
|
||||
children: [
|
||||
{ label: '1#插入量', col: 'TLMESH1' },
|
||||
{ label: '2#插入量', col: 'TLMESH2' },
|
||||
{ label: '3#插入量', col: 'TLMESH3' },
|
||||
{ label: '延伸率', col: 'TLELONG' }
|
||||
]
|
||||
},
|
||||
{
|
||||
label: '酸洗段',
|
||||
children: [
|
||||
{ label: '1#温度', col: 'TK1TEMP' },
|
||||
{ label: '2#温度', col: 'TK2TEMP' },
|
||||
{ label: '3#温度', col: 'TK3TEMP' },
|
||||
{ label: '漂洗温度', col: 'RINSETEMP' }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
// V_VBDA_GAUGE 厚度曲线:4 个图,列名来自 DDL
|
||||
const GAUGE_COLS = [
|
||||
{ col: 'THICK0', title: '入口测厚仪 [mm]' },
|
||||
{ col: 'THICK1', title: '1架出口厚度 [mm]' },
|
||||
{ col: 'THICK4', title: '末架出口厚度 [mm]' },
|
||||
{ col: 'EXIT_SPEED', title: '轧制速度 [m/min]' }
|
||||
]
|
||||
|
||||
// V_VBDA_SHAPE 板形曲线:4 个图,列名来自 DDL
|
||||
const SHAPE_SCALAR_COLS = [
|
||||
{ col: 'ABSDEVIATION', title: '总板形偏差 [IU]' },
|
||||
{ col: 'TILT', title: '末架倾斜量 [mm]' },
|
||||
{ col: 'WRBEND', title: '工作辊弯辊力 [kN]' },
|
||||
{ col: 'IRBEND', title: '中间辊弯辊力 [kN]' }
|
||||
]
|
||||
|
||||
/**
|
||||
* 从数据数组计算合理的 Y 轴范围(带 15% 上下边距)。
|
||||
* echarts 默认 scale 在数据变化幅度极小时会把轴拉到很大范围,导致曲线看起来是横线。
|
||||
*/
|
||||
function calcYRange(vals) {
|
||||
const nums = vals.filter(v => v != null && isFinite(Number(v))).map(Number)
|
||||
if (!nums.length) return {}
|
||||
const min = Math.min(...nums)
|
||||
const max = Math.max(...nums)
|
||||
if (min === max) {
|
||||
const base = Math.abs(min) || 1
|
||||
return { min: parseFloat((min - base * 0.2).toFixed(4)), max: parseFloat((max + base * 0.2).toFixed(4)) }
|
||||
}
|
||||
const pad = (max - min) * 0.15
|
||||
return {
|
||||
min: parseFloat((min - pad).toFixed(4)),
|
||||
max: parseFloat((max + pad).toFixed(4))
|
||||
}
|
||||
}
|
||||
|
||||
function makeLine(title, xData, yData) {
|
||||
const range = calcYRange(yData)
|
||||
return {
|
||||
title: { text: title, textStyle: { fontSize: 12, fontWeight: 'normal' }, top: 4, left: 8 },
|
||||
tooltip: { trigger: 'axis' },
|
||||
grid: { top: 36, bottom: 28, left: 8, right: 16, containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category', data: xData,
|
||||
name: 'pos(m)', nameTextStyle: { fontSize: 10 }, axisLabel: { fontSize: 10 }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: range.min,
|
||||
max: range.max,
|
||||
nameTextStyle: { fontSize: 10 },
|
||||
axisLabel: { fontSize: 10 }
|
||||
},
|
||||
dataZoom: [
|
||||
{ type: 'inside', xAxisIndex: 0, zoomOnMouseWheel: true, moveOnMouseMove: true },
|
||||
{ type: 'inside', yAxisIndex: 0, zoomOnMouseWheel: false, moveOnMouseWheel: true }
|
||||
],
|
||||
series: [{
|
||||
name: title, type: 'line', smooth: false, symbol: 'none',
|
||||
lineStyle: { width: 1 }, data: yData
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
function getRowVal(row, col) {
|
||||
const v = row[col] !== undefined ? row[col] : row[col.toLowerCase()]
|
||||
return v == null ? null : Number(v)
|
||||
}
|
||||
|
||||
function xLocData(rows) {
|
||||
return rows.map(r => {
|
||||
const v = r.XLOCATION !== undefined ? r.XLOCATION : r.xlocation
|
||||
return v == null ? '' : Number(v).toFixed(1)
|
||||
})
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'ActualPerformance',
|
||||
data() {
|
||||
return {
|
||||
excoilLoading: false,
|
||||
segLoading: false,
|
||||
realtimeLoading: false,
|
||||
excoilRows: [],
|
||||
selectedRow: null,
|
||||
segData: null,
|
||||
gaugeRows: null,
|
||||
shapeRows: null,
|
||||
activeTab: 'trend',
|
||||
// 趋势参数树状态
|
||||
trendGroups: TREND_GROUPS,
|
||||
expandedGroups: { '张力': true, '速度': true, '拉矫机': true, '酸洗段': true },
|
||||
selectedTrendParam: null,
|
||||
trendChartInst: null,
|
||||
// 查找
|
||||
searchType: 'coil',
|
||||
searchCoilId: '',
|
||||
searchStartDate: '',
|
||||
searchEndDate: '',
|
||||
pagination: { page: 1, pageSize: 50, total: 0 },
|
||||
topTableHeight: 'calc(40vh - 80px)',
|
||||
chartInstances: [],
|
||||
resizeHandler: null
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.loadExcoilCount()
|
||||
this.loadExcoilList()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.disposeAllCharts()
|
||||
},
|
||||
methods: {
|
||||
async loadExcoilCount() {
|
||||
try {
|
||||
const res = await getExcoilCount()
|
||||
this.pagination.total = res?.data?.total ?? 0
|
||||
} catch (_) {}
|
||||
},
|
||||
async loadExcoilList() {
|
||||
this.excoilLoading = true
|
||||
try {
|
||||
const res = await getExcoilList(this.pagination.page, this.pagination.pageSize)
|
||||
this.excoilRows = res?.data?.rows || []
|
||||
} finally {
|
||||
this.excoilLoading = false
|
||||
}
|
||||
},
|
||||
handlePageChange(page) {
|
||||
this.pagination.page = page
|
||||
this.loadExcoilList()
|
||||
},
|
||||
async handleRowClick(row) {
|
||||
this.selectedRow = row
|
||||
this.segData = null
|
||||
this.gaugeRows = null
|
||||
this.shapeRows = null
|
||||
this.selectedTrendParam = null
|
||||
this.disposeAllCharts()
|
||||
|
||||
// PLTCM_PRO_SEG 用 ENCOILID 查(主键前缀)
|
||||
const encoilId = row.ENCOILID || row.encoilid
|
||||
// V_VBDA_GAUGE / V_VBDA_SHAPE 用 EXCOILID 作为 MATID
|
||||
const excoilId = row.EXCOILID || row.excoilid
|
||||
|
||||
await Promise.all([
|
||||
encoilId ? this.loadSeg(encoilId) : Promise.resolve(),
|
||||
excoilId ? this.loadRealtime(excoilId) : Promise.resolve()
|
||||
])
|
||||
|
||||
await this.$nextTick()
|
||||
// 加载完成后自动选中第一个趋势参数
|
||||
if (this.activeTab === 'trend' && this.segData) {
|
||||
this.selectTrendParam(TREND_GROUPS[0].children[0])
|
||||
} else {
|
||||
this.renderCurrentTab()
|
||||
}
|
||||
},
|
||||
|
||||
async loadSeg(encoilId) {
|
||||
this.segLoading = true
|
||||
try {
|
||||
const res = await getTimingSegByEncoilId(encoilId)
|
||||
const rows = res?.data?.rows || []
|
||||
this.segData = rows.length ? (res?.data?.series || null) : null
|
||||
} catch (_) {
|
||||
} finally {
|
||||
this.segLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
async loadRealtime(excoilId) {
|
||||
this.realtimeLoading = true
|
||||
try {
|
||||
const res = await getTimingRealtimeData(excoilId)
|
||||
const g = res?.data?.gauge?.result
|
||||
const s = res?.data?.shape?.result
|
||||
this.gaugeRows = Array.isArray(g) ? g : null
|
||||
this.shapeRows = Array.isArray(s) ? s : null
|
||||
} catch (_) {
|
||||
} finally {
|
||||
this.realtimeLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
// ── 趋势参数树 ──────────────────────────────
|
||||
toggleGroup(label) {
|
||||
this.$set(this.expandedGroups, label, !this.expandedGroups[label])
|
||||
},
|
||||
isGroupExpanded(label) {
|
||||
return !!this.expandedGroups[label]
|
||||
},
|
||||
selectTrendParam(item) {
|
||||
this.selectedTrendParam = item
|
||||
this.$nextTick(() => this.renderTrendSingleChart())
|
||||
},
|
||||
renderTrendSingleChart() {
|
||||
if (!this.selectedTrendParam || !this.segData) return
|
||||
const el = this.$refs.trendSingleChart
|
||||
if (!el) return
|
||||
// 复用已有实例,避免重复 init
|
||||
if (!this.trendChartInst || this.trendChartInst.isDisposed()) {
|
||||
this.trendChartInst = echarts.init(el)
|
||||
// 滚轮缩放支持
|
||||
const resizeFn = () => this.trendChartInst && !this.trendChartInst.isDisposed() && this.trendChartInst.resize()
|
||||
window.addEventListener('resize', resizeFn)
|
||||
this._trendResizeFn = resizeFn
|
||||
}
|
||||
const x = this.segX()
|
||||
const yData = this.seg(this.selectedTrendParam.col)
|
||||
this.trendChartInst.setOption(makeLine(this.selectedTrendParam.label, x, yData), true)
|
||||
},
|
||||
|
||||
// ── Tab 切换 ────────────────────────────────
|
||||
handleTabSwitch() {
|
||||
this.$nextTick(() => {
|
||||
if (this.activeTab === 'trend' && this.selectedTrendParam && this.segData) {
|
||||
this.renderTrendSingleChart()
|
||||
} else {
|
||||
this.renderCurrentTab()
|
||||
}
|
||||
})
|
||||
},
|
||||
renderCurrentTab() {
|
||||
this.disposeSideCharts()
|
||||
if (this.activeTab === 'thickness' && this.gaugeRows?.length) this.renderGaugeCharts()
|
||||
if (this.activeTab === 'flatness3d' && this.shapeRows?.length) this.renderFlatness3d()
|
||||
if (this.activeTab === 'flatness' && this.shapeRows?.length) this.renderFlatnessCharts()
|
||||
},
|
||||
|
||||
// ── 销毁 ────────────────────────────────────
|
||||
disposeSideCharts() {
|
||||
if (this.resizeHandler) {
|
||||
window.removeEventListener('resize', this.resizeHandler)
|
||||
this.resizeHandler = null
|
||||
}
|
||||
this.chartInstances.forEach(c => { if (c && !c.isDisposed()) c.dispose() })
|
||||
this.chartInstances = []
|
||||
},
|
||||
disposeAllCharts() {
|
||||
this.disposeSideCharts()
|
||||
if (this._trendResizeFn) {
|
||||
window.removeEventListener('resize', this._trendResizeFn)
|
||||
this._trendResizeFn = null
|
||||
}
|
||||
if (this.trendChartInst && !this.trendChartInst.isDisposed()) {
|
||||
this.trendChartInst.dispose()
|
||||
this.trendChartInst = null
|
||||
}
|
||||
},
|
||||
|
||||
// ── SEG 数据辅助 ─────────────────────────────
|
||||
seg(col) {
|
||||
const s = this.segData
|
||||
// Oracle 返回大写列名,兼容小写
|
||||
const arr = s[col] !== undefined ? s[col] : (s[col.toLowerCase()] || [])
|
||||
return arr.map(v => v == null ? null : Number(Number(v).toFixed(3)))
|
||||
},
|
||||
segX() {
|
||||
const s = this.segData
|
||||
const arr = s['STARTPOS'] !== undefined ? s['STARTPOS'] : (s['startpos'] || [])
|
||||
return arr.map(v => v == null ? '' : Number(v).toFixed(1))
|
||||
},
|
||||
|
||||
// ── 图表初始化 ───────────────────────────────
|
||||
makeChart(ref, option) {
|
||||
const el = this.$refs[ref]
|
||||
if (!el) return null
|
||||
const chart = echarts.init(el)
|
||||
chart.setOption(option)
|
||||
return chart
|
||||
},
|
||||
setupResize() {
|
||||
this.resizeHandler = () => this.chartInstances.forEach(c => {
|
||||
if (c && !c.isDisposed()) c.resize()
|
||||
})
|
||||
window.addEventListener('resize', this.resizeHandler)
|
||||
},
|
||||
|
||||
// ── 厚度曲线 (V_VBDA_GAUGE) ──────────────────
|
||||
renderGaugeCharts() {
|
||||
const rows = this.gaugeRows
|
||||
if (!rows || !rows.length) return
|
||||
const xData = xLocData(rows)
|
||||
const refs = ['chartGauge1', 'chartGauge2', 'chartGauge3', 'chartGauge4']
|
||||
const charts = refs.map((ref, i) => {
|
||||
const { col, title } = GAUGE_COLS[i]
|
||||
const yData = rows.map(r => {
|
||||
const v = getRowVal(r, col)
|
||||
return v == null ? null : parseFloat(v.toFixed(4))
|
||||
})
|
||||
return this.makeChart(ref, makeLine(title, xData, yData))
|
||||
})
|
||||
this.chartInstances = charts.filter(Boolean)
|
||||
this.setupResize()
|
||||
},
|
||||
|
||||
// ── 带钢板形 3D 线图 (V_VBDA_SHAPE) ────────────
|
||||
// 每个通道画一条独立 line3D,通道之间不连面,形成镂空效果
|
||||
renderFlatness3d() {
|
||||
const rows = this.shapeRows
|
||||
if (!rows || !rows.length) return
|
||||
const firstRow = rows[0]
|
||||
const high = parseInt(getRowVal(firstRow, 'HIGHZONEID')) || 26
|
||||
const low = parseInt(getRowVal(firstRow, 'LOWZONEID')) || 1
|
||||
const numZones = Math.min(Math.max(high - low + 1, 1), 26)
|
||||
const zoneCols = Array.from({ length: numZones }, (_, i) =>
|
||||
`VALUES${String(low + i).padStart(2, '0')}`
|
||||
)
|
||||
// X 方向降采样,最多 200 个点
|
||||
const step = Math.max(1, Math.floor(rows.length / 200))
|
||||
const sampled = rows.filter((_, i) => i % step === 0)
|
||||
const numX = sampled.length
|
||||
|
||||
// X 轴标签(位置,单位 m)
|
||||
const xLabels = sampled.map(r => {
|
||||
const v = r.XLOCATION !== undefined ? r.XLOCATION : r.xlocation
|
||||
return v == null ? '' : Number(v).toFixed(0)
|
||||
})
|
||||
|
||||
// 收集值域用于 visualMap
|
||||
let minV = Infinity, maxV = -Infinity
|
||||
sampled.forEach(row => {
|
||||
zoneCols.forEach(col => {
|
||||
const v = getRowVal(row, col)
|
||||
if (v != null) {
|
||||
if (v < minV) minV = v
|
||||
if (v > maxV) maxV = v
|
||||
}
|
||||
})
|
||||
})
|
||||
if (!isFinite(minV)) { minV = -30; maxV = 30 }
|
||||
const absMax = Math.max(Math.abs(minV), Math.abs(maxV))
|
||||
|
||||
// ① 沿 X 方向网格线(每通道一条,按 Z 值着色)
|
||||
const channelLines = zoneCols.map((col, yi) => ({
|
||||
type: 'line3D',
|
||||
coordinateSystem: 'cartesian3D',
|
||||
data: sampled.map((row, xi) => {
|
||||
const v = getRowVal(row, col)
|
||||
return v == null ? null : [xi, yi, parseFloat(v.toFixed(2))]
|
||||
}).filter(Boolean),
|
||||
lineStyle: { width: 2, opacity: 1 }
|
||||
}))
|
||||
|
||||
// ② 沿 Y 方向网格线(每隔若干位置连通各通道,按 Z 值着色)
|
||||
const xStride = Math.max(1, Math.floor(numX / 60))
|
||||
const crossLines = []
|
||||
for (let xi = 0; xi < numX; xi += xStride) {
|
||||
const pts = zoneCols.map((col, yi) => {
|
||||
const v = getRowVal(sampled[xi], col)
|
||||
return v == null ? null : [xi, yi, parseFloat(v.toFixed(2))]
|
||||
}).filter(Boolean)
|
||||
if (pts.length > 1) {
|
||||
crossLines.push({
|
||||
type: 'line3D',
|
||||
coordinateSystem: 'cartesian3D',
|
||||
data: pts,
|
||||
lineStyle: { width: 1.5, opacity: 1 }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const series = [...channelLines, ...crossLines]
|
||||
|
||||
const option = {
|
||||
title: { text: '实测平直度 [IU]', textStyle: { fontSize: 13, fontWeight: 'normal' }, top: 6, left: 10 },
|
||||
tooltip: {},
|
||||
visualMap: {
|
||||
show: true,
|
||||
dimension: 2,
|
||||
min: -absMax,
|
||||
max: absMax,
|
||||
calculable: true,
|
||||
orient: 'vertical',
|
||||
right: 10,
|
||||
top: 'center',
|
||||
textStyle: { fontSize: 10 },
|
||||
inRange: {
|
||||
// 负值红色 → 零值绿色 → 正值蓝紫
|
||||
color: ['#8B0000','#CC2200','#E84C00','#F46D43',
|
||||
'#FDAE61','#FEE08B',
|
||||
'#66BD63','#1A9850','#006837',
|
||||
'#3288BD','#5E4FA2','#762A83']
|
||||
}
|
||||
},
|
||||
grid3D: {
|
||||
boxWidth: 200,
|
||||
boxHeight: 60,
|
||||
boxDepth: 80,
|
||||
viewControl: {
|
||||
projection: 'orthographic',
|
||||
autoRotate: false,
|
||||
rotateSensitivity: 1,
|
||||
zoomSensitivity: 1
|
||||
},
|
||||
light: {
|
||||
main: { intensity: 1.2, shadow: false },
|
||||
ambient: { intensity: 0.3 }
|
||||
}
|
||||
},
|
||||
xAxis3D: {
|
||||
type: 'value',
|
||||
name: '位置',
|
||||
min: 0,
|
||||
max: numX - 1,
|
||||
nameTextStyle: { fontSize: 10 },
|
||||
axisLabel: {
|
||||
fontSize: 9,
|
||||
formatter: v => xLabels[Math.round(v)] || ''
|
||||
}
|
||||
},
|
||||
yAxis3D: {
|
||||
type: 'value',
|
||||
name: '通道',
|
||||
min: 0,
|
||||
max: numZones - 1,
|
||||
nameTextStyle: { fontSize: 10 },
|
||||
axisLabel: {
|
||||
fontSize: 9,
|
||||
formatter: v => String(low + Math.round(v))
|
||||
}
|
||||
},
|
||||
zAxis3D: {
|
||||
type: 'value',
|
||||
name: 'IU',
|
||||
nameTextStyle: { fontSize: 10 },
|
||||
axisLabel: { fontSize: 9 }
|
||||
},
|
||||
series
|
||||
}
|
||||
|
||||
const el = this.$refs.chartFlatness3d
|
||||
if (!el) return
|
||||
const chart = echarts.init(el)
|
||||
chart.setOption(option)
|
||||
this.chartInstances = [chart]
|
||||
this.setupResize()
|
||||
},
|
||||
|
||||
// ── 板形曲线 (V_VBDA_SHAPE) ──────────────────
|
||||
renderFlatnessCharts() {
|
||||
const rows = this.shapeRows
|
||||
if (!rows || !rows.length) return
|
||||
const xData = xLocData(rows)
|
||||
const refs = ['chartFlatDev', 'chartTilt', 'chartWrBend', 'chartIrBend']
|
||||
const charts = refs.map((ref, i) => {
|
||||
const { col, title } = SHAPE_SCALAR_COLS[i]
|
||||
const yData = rows.map(r => {
|
||||
const v = getRowVal(r, col)
|
||||
return v == null ? null : parseFloat(v.toFixed(3))
|
||||
})
|
||||
return this.makeChart(ref, makeLine(title, xData, yData))
|
||||
})
|
||||
this.chartInstances = charts.filter(Boolean)
|
||||
this.setupResize()
|
||||
},
|
||||
|
||||
// ── 查找 ─────────────────────────────────────
|
||||
handleFindSearch() {
|
||||
if (this.searchType === 'coil' && this.searchCoilId) {
|
||||
const found = this.excoilRows.find(r =>
|
||||
(r.EXCOILID || r.excoilid || '').includes(this.searchCoilId)
|
||||
)
|
||||
if (found) {
|
||||
this.$refs.excoilTable && this.$refs.excoilTable.setCurrentRow(found)
|
||||
this.handleRowClick(found)
|
||||
} else {
|
||||
this.$message.info('当前页未找到该卷号,请翻页查找')
|
||||
}
|
||||
} else {
|
||||
this.pagination.page = 1
|
||||
this.loadExcoilList()
|
||||
}
|
||||
},
|
||||
handleFindReset() {
|
||||
this.searchCoilId = ''
|
||||
this.searchStartDate = ''
|
||||
this.searchEndDate = ''
|
||||
this.selectedRow = null
|
||||
this.segData = null
|
||||
this.gaugeRows = null
|
||||
this.shapeRows = null
|
||||
this.selectedTrendParam = null
|
||||
this.disposeAllCharts()
|
||||
this.pagination.page = 1
|
||||
this.loadExcoilCount()
|
||||
this.loadExcoilList()
|
||||
},
|
||||
|
||||
calcLengthPerTon(row) {
|
||||
const len = parseFloat(row.EXIT_LENGTH || row.exit_length)
|
||||
const wt = parseFloat(row.MEAS_EXIT_WEIGHT || row.meas_exit_weight)
|
||||
if (!len || !wt || wt === 0) return '—'
|
||||
return (len / wt).toFixed(2)
|
||||
},
|
||||
formatDate(v) {
|
||||
if (!v) return '—'
|
||||
return String(v).replace('T', ' ').substring(0, 19)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.actual-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 8px;
|
||||
background: #f0f2f5;
|
||||
gap: 6px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.top-section {
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-pagination {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding: 4px 8px;
|
||||
border-top: 1px solid #ebeef5;
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.bottom-section {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
display: flex;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.chart-section {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
|
||||
.chart-tabs {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 0;
|
||||
|
||||
::v-deep .el-tabs__content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
::v-deep .el-tab-pane {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ── 趋势参数:左树 + 右图 ── */
|
||||
.trend-layout {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.trend-tree {
|
||||
width: 140px;
|
||||
flex-shrink: 0;
|
||||
overflow-y: auto;
|
||||
border-right: 1px solid #ebeef5;
|
||||
padding: 4px 0;
|
||||
|
||||
&::-webkit-scrollbar { width: 3px; }
|
||||
&::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 2px; }
|
||||
}
|
||||
|
||||
.tree-group {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.tree-group-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 5px 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover { background: #f5f7fa; }
|
||||
|
||||
i { font-size: 10px; color: #909399; }
|
||||
}
|
||||
|
||||
.tree-children { padding-left: 4px; }
|
||||
|
||||
.tree-item {
|
||||
padding: 4px 8px 4px 18px;
|
||||
font-size: 12px;
|
||||
color: #606266;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
margin: 1px 4px;
|
||||
|
||||
&:hover { background: #ecf5ff; color: #409eff; }
|
||||
|
||||
&.active {
|
||||
background: #ecf5ff;
|
||||
color: #409eff;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.trend-chart-area {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
padding: 4px 4px 4px 8px;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
/* ── 其他图表 ── */
|
||||
.charts-scroll {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
padding: 4px;
|
||||
|
||||
&::-webkit-scrollbar { width: 4px; }
|
||||
&::-webkit-scrollbar-thumb { background: #dcdfe6; border-radius: 2px; }
|
||||
}
|
||||
|
||||
/* 一行两图 */
|
||||
.charts-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
align-content: start;
|
||||
|
||||
.chart-box { margin-bottom: 0; }
|
||||
}
|
||||
|
||||
.chart-box {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.chart-box-tall { height: 480px; }
|
||||
|
||||
/* ── 查找面板 ── */
|
||||
.search-panel {
|
||||
width: 210px;
|
||||
flex-shrink: 0;
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 4px rgba(0,0,0,0.06);
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 14px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.panel-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
padding-bottom: 6px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.search-type-group { display: flex; flex-direction: column; gap: 8px; }
|
||||
|
||||
.search-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.search-label { font-size: 11px; color: #909399; }
|
||||
|
||||
.search-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.no-data-hint {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
color: #c0c4cc;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -27,7 +27,11 @@
|
||||
<span slot="title">品质</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="performance">
|
||||
<i class="el-icon-coin"></i>
|
||||
<i class="el-icon-date"></i>
|
||||
<span slot="title">计划</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="actualPerformance">
|
||||
<i class="el-icon-data-analysis"></i>
|
||||
<span slot="title">实绩</span>
|
||||
</el-menu-item>
|
||||
<el-menu-item index="rollConfig">
|
||||
@@ -42,13 +46,9 @@
|
||||
<i class="el-icon-warning"></i>
|
||||
<span slot="title">停机</span>
|
||||
</el-menu-item>
|
||||
<!-- <el-menu-item index="realTime">
|
||||
<i class="el-icon-time"></i>
|
||||
<span slot="title">实时</span>
|
||||
</el-menu-item> -->
|
||||
</el-menu>
|
||||
</div>
|
||||
<div style="flex: 1;">
|
||||
<div style="flex: 1; overflow: hidden;">
|
||||
<component :is="currentComponent" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,7 +61,7 @@ import Report from './components/Report.vue';
|
||||
import Shipping from './components/Shipping.vue';
|
||||
import Quality from './components/Quality.vue';
|
||||
import Performance from './components/Performance.vue';
|
||||
import RealTime from './components/RealTime.vue';
|
||||
import ActualPerformance from './components/ActualPerformance.vue';
|
||||
import RollConfig from '@/views/timing/roll/index.vue';
|
||||
import RollHistory from '@/views/timing/roll/history.vue';
|
||||
import Stoppage from '@/views/timing/stoppage/index.vue';
|
||||
@@ -75,7 +75,7 @@ export default {
|
||||
Shipping,
|
||||
Quality,
|
||||
Performance,
|
||||
RealTime,
|
||||
ActualPerformance,
|
||||
RollConfig,
|
||||
RollHistory,
|
||||
Stoppage
|
||||
@@ -94,7 +94,7 @@ export default {
|
||||
shipping: 'Shipping',
|
||||
quality: 'Quality',
|
||||
performance: 'Performance',
|
||||
realTime: 'RealTime',
|
||||
actualPerformance: 'ActualPerformance',
|
||||
rollConfig: 'RollConfig',
|
||||
rollHistory: 'RollHistory',
|
||||
stoppage: 'Stoppage',
|
||||
|
||||
@@ -766,7 +766,7 @@ import { listTransferOrderItem } from '@/api/wms/transferOrderItem'
|
||||
import { listCoilQualityRejudge } from '@/api/wms/coilQualityRejudge'
|
||||
// 引入 ECharts 和 L2 时序数据 API
|
||||
import * as echarts from 'echarts'
|
||||
import { getTimingSegByEncoilId } from '@/api/l2/timing'
|
||||
import { getTimingSegByEncoilId, getTimingPlanDetailByHotcoilId } from '@/api/l2/timing'
|
||||
|
||||
import AbnormalTable from '@/views/wms/coil/components/AbnormalTable.vue';
|
||||
import FileList from "@/components/FileList";
|
||||
@@ -1176,11 +1176,16 @@ export default {
|
||||
},
|
||||
// 加载生产数据
|
||||
async loadProductionData() {
|
||||
const encoilId = this.coilInfo.currentCoilNo;
|
||||
if (!encoilId) return;
|
||||
const hotCoilId = this.coilInfo.enterCoilNo;
|
||||
if (!hotCoilId) return;
|
||||
|
||||
this.perfLoading = true;
|
||||
try {
|
||||
// 先查询详情
|
||||
const detail = await getTimingPlanDetailByHotcoilId(hotCoilId);
|
||||
const encoilId = detail?.data?.firstRow?.coilid || '';
|
||||
if (!encoilId) return;
|
||||
|
||||
const res = await getTimingSegByEncoilId(encoilId);
|
||||
const series = res?.data?.series || null;
|
||||
const rows = res?.data?.rows || [];
|
||||
|
||||
@@ -607,6 +607,178 @@
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 钢卷暂存单据管理 -->
|
||||
<el-card class="box-card" style="margin-top: 20px;" :body-style="{ padding: '20px' }">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>钢卷暂存单据管理</span>
|
||||
<el-button style="float: right; padding: 3px 0" type="text" @click="createTempOrder">创建暂存单据</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 暂存单据列表 -->
|
||||
<el-table :data="tempOrderList" style="width: 100%" :height="'calc(100vh - 500px)'">
|
||||
<el-table-column prop="orderName" label="单据名称">
|
||||
<template slot-scope="scope">
|
||||
<div style="display: flex; align-items: center; gap: 5px;">
|
||||
<el-link type="primary" @click="viewSelectedCoils(scope.row)">{{ scope.row.orderName }}</el-link>
|
||||
<el-button size="mini" type="text" icon="el-icon-edit" @click="editOrderName(scope.row)"></el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="创建时间"></el-table-column>
|
||||
<el-table-column prop="coilCount" label="钢卷数量">
|
||||
<template slot-scope="scope">
|
||||
<el-tag size="small">{{ (scope.row.coils && scope.row.coils.length) ? scope.row.coils.length : 0 }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="totalWeight" label="总重量(t)">
|
||||
<template slot-scope="scope">
|
||||
{{ calculateTotalWeight(scope.row.coils || []).toFixed(3) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" @click="openCoilSelection(scope.row)">选择钢卷</el-button>
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;" @click="deleteTempOrder(scope.row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 当没有数据时显示提示 -->
|
||||
<div v-if="!tempOrderList || tempOrderList.length === 0" style="text-align: center; padding: 50px; color: #909399;">
|
||||
<i class="el-icon-document" style="font-size: 48px; margin-bottom: 10px;"></i>
|
||||
<div>暂无暂存单据</div>
|
||||
<div style="font-size: 12px; margin-top: 5px;">点击右上角"创建暂存单据"开始使用</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 钢卷选择对话框 -->
|
||||
<el-dialog title="选择钢卷" :visible.sync="coilSelectionVisible" width="95%" append-to-body>
|
||||
<!-- 上方:查询条件 -->
|
||||
<el-card class="query-card" style="margin-bottom: 15px;">
|
||||
<el-form :model="coilQueryParams" size="small" :inline="true">
|
||||
<el-form-item label="入场卷号">
|
||||
<el-input v-model="coilQueryParams.enterCoilNo" placeholder="请输入入场钢卷号" clearable style="width: 200px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="当前卷号">
|
||||
<el-input v-model="coilQueryParams.currentCoilNo" placeholder="请输入当前钢卷号" clearable style="width: 200px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称">
|
||||
<el-input v-model="coilQueryParams.itemName" placeholder="请选择物料" clearable style="width: 200px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规格">
|
||||
<el-input v-model="coilQueryParams.itemSpecification" placeholder="请选择规格" clearable style="width: 200px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="材质">
|
||||
<el-input v-model="coilQueryParams.itemMaterial" placeholder="请选择材质" clearable style="width: 200px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="searchCoils">查询</el-button>
|
||||
<el-button @click="resetCoilQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
|
||||
<!-- 下方:钢卷列表 -->
|
||||
<div style="height: 500px;">
|
||||
<el-table v-loading="coilLoading" :data="availableCoils" @selection-change="handleCoilSelection" border height="450">
|
||||
<el-table-column type="selection" width="55" align="center" />
|
||||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||||
<template slot-scope="scope">
|
||||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
|
||||
<template slot-scope="scope">
|
||||
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="净重" align="center" prop="netWeight" />
|
||||
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
|
||||
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
|
||||
<el-table-column label="产品类型" align="center" width="180">
|
||||
<template slot-scope="scope">
|
||||
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
|
||||
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" prop="specification"></el-table-column>
|
||||
<el-table-column label="物料" prop="itemName"></el-table-column>
|
||||
<el-table-column label="材质" prop="material"></el-table-column>
|
||||
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
|
||||
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
|
||||
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
|
||||
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
|
||||
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
|
||||
<el-table-column label="状态" align="center" prop="status">
|
||||
<template slot-scope="scope">
|
||||
<el-tag v-if="scope.row.status === 0" type="info" size="mini">未发货</el-tag>
|
||||
<el-tag v-else type="success" size="mini">已发货</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
</el-table>
|
||||
|
||||
<div style="margin-top: 10px; text-align: center;">
|
||||
<el-pagination
|
||||
@size-change="handleCoilSizeChange"
|
||||
@current-change="handleCoilCurrentChange"
|
||||
:current-page="coilQueryParams.pageNum"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
:page-size="coilQueryParams.pageSize"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="coilTotal">
|
||||
</el-pagination>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<div style="margin-bottom: 10px;">
|
||||
<span>已选择 {{ selectedCoils.length }} 个钢卷,总重量:{{ calculateSelectedWeight().toFixed(3) }}t</span>
|
||||
</div>
|
||||
<el-button @click="coilSelectionVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="saveSelectedCoils">确认选择</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 已选钢卷列表对话框 -->
|
||||
<el-dialog title="已选钢卷列表" :visible.sync="selectedCoilsVisible" width="90%" append-to-body>
|
||||
<el-table :data="currentTempOrder ? (currentTempOrder.coils || []) : []" border>
|
||||
<el-table-column label="入场钢卷号" align="center" prop="enterCoilNo">
|
||||
<template slot-scope="scope">
|
||||
<coil-no :coil-no="scope.row.enterCoilNo"></coil-no>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="当前钢卷号" align="center" prop="currentCoilNo">
|
||||
<template slot-scope="scope">
|
||||
<current-coil-no :current-coil-no="scope.row.currentCoilNo"></current-coil-no>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="净重" align="center" prop="netWeight" />
|
||||
<el-table-column label="逻辑库位" align="center" prop="warehouseName" />
|
||||
<el-table-column label="实际库区" align="center" prop="actualWarehouseName" />
|
||||
<el-table-column label="产品类型" align="center" width="180">
|
||||
<template slot-scope="scope">
|
||||
<ProductInfo v-if="scope.row.itemType == 'product'" :product="scope.row" />
|
||||
<RawMaterialInfo v-else-if="scope.row.itemType === 'raw_material'" :material="scope.row" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="规格" prop="specification"></el-table-column>
|
||||
<el-table-column label="物料" prop="itemName"></el-table-column>
|
||||
<el-table-column label="材质" prop="material"></el-table-column>
|
||||
<el-table-column label="厂家" prop="manufacturer"></el-table-column>
|
||||
<el-table-column label="表面处理" prop="surfaceTreatmentDesc"></el-table-column>
|
||||
<el-table-column label="品质" prop="qualityStatus"></el-table-column>
|
||||
<el-table-column label="切边" prop="trimmingRequirement"></el-table-column>
|
||||
<el-table-column label="包装" prop="packagingRequirement"></el-table-column>
|
||||
<el-table-column label="备注" align="center" prop="remark" show-overflow-tooltip />
|
||||
<el-table-column label="操作" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" style="color: #f56c6c;" @click="removeCoilFromOrder(scope.$index)">移除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -994,6 +1166,31 @@ export default {
|
||||
// 调拨记录弹窗
|
||||
transferRecordVisible: false,
|
||||
transferRecordList: [],
|
||||
// 暂存单据管理相关数据
|
||||
tempOrderList: [],
|
||||
currentTempOrder: null,
|
||||
coilSelectionVisible: false,
|
||||
selectedCoilsVisible: false,
|
||||
coilLoading: false,
|
||||
availableCoils: [],
|
||||
selectedCoils: [],
|
||||
coilTotal: 0,
|
||||
coilQueryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
itemName: '',
|
||||
itemSpecification: '',
|
||||
itemMaterial: '',
|
||||
status: 0,
|
||||
orderBy: true,
|
||||
dataType: 1,
|
||||
materialType: '成品',
|
||||
itemType: 'product',
|
||||
excludeBound: true,
|
||||
selectType: 'product'
|
||||
},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@@ -1021,8 +1218,257 @@ export default {
|
||||
this.warehouseIds = this.warehouseOptions.map(item => item.value).join(',');
|
||||
}
|
||||
this.getList();
|
||||
// 初始化暂存单据列表
|
||||
this.loadTempOrderList();
|
||||
},
|
||||
methods: {
|
||||
// === 暂存单据管理相关方法 ===
|
||||
// 加载暂存单据列表
|
||||
loadTempOrderList() {
|
||||
const savedOrders = localStorage.getItem('tempCoilOrders');
|
||||
if (savedOrders) {
|
||||
this.tempOrderList = JSON.parse(savedOrders);
|
||||
} else {
|
||||
this.tempOrderList = [];
|
||||
}
|
||||
},
|
||||
|
||||
// 保存暂存单据列表到本地存储
|
||||
saveTempOrderList() {
|
||||
localStorage.setItem('tempCoilOrders', JSON.stringify(this.tempOrderList));
|
||||
},
|
||||
|
||||
// 创建暂存单据
|
||||
createTempOrder() {
|
||||
const orderName = `暂存单据_${new Date().toLocaleString().replace(/[/:]/g, '-')}`;
|
||||
const newOrder = {
|
||||
orderId: Date.now().toString(),
|
||||
orderName: orderName,
|
||||
createTime: new Date().toLocaleString(),
|
||||
coils: []
|
||||
};
|
||||
|
||||
this.tempOrderList.unshift(newOrder);
|
||||
this.saveTempOrderList();
|
||||
|
||||
this.$message.success('暂存单据创建成功');
|
||||
},
|
||||
|
||||
// 删除暂存单据
|
||||
deleteTempOrder(order) {
|
||||
this.$confirm(`确认删除暂存单据"${order.orderName}"吗?`, '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
const index = this.tempOrderList.findIndex(item => item.orderId === order.orderId);
|
||||
if (index > -1) {
|
||||
this.tempOrderList.splice(index, 1);
|
||||
this.saveTempOrderList();
|
||||
this.$message.success('删除成功');
|
||||
}
|
||||
}).catch(() => {
|
||||
this.$message.info('已取消删除');
|
||||
});
|
||||
},
|
||||
|
||||
// 查看已选钢卷列表
|
||||
viewSelectedCoils(order) {
|
||||
this.currentTempOrder = order;
|
||||
this.selectedCoilsVisible = true;
|
||||
},
|
||||
|
||||
// 编辑单据名称
|
||||
editOrderName(order) {
|
||||
this.$prompt('请输入新的单据名称', '编辑单据名称', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
inputValue: order.orderName,
|
||||
inputValidator: (value) => {
|
||||
if (!value || value.trim() === '') {
|
||||
return '单据名称不能为空';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}).then(({ value }) => {
|
||||
const newName = value.trim();
|
||||
// 检查名称是否重复
|
||||
const duplicateOrder = this.tempOrderList.find(item =>
|
||||
item.orderId !== order.orderId && item.orderName === newName
|
||||
);
|
||||
|
||||
if (duplicateOrder) {
|
||||
this.$message.warning('单据名称已存在,请使用其他名称');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新单据名称
|
||||
order.orderName = newName;
|
||||
this.saveTempOrderList();
|
||||
this.$message.success('单据名称修改成功');
|
||||
}).catch(() => {
|
||||
this.$message.info('已取消编辑');
|
||||
});
|
||||
},
|
||||
|
||||
// 打开钢卷选择对话框
|
||||
openCoilSelection(order) {
|
||||
this.currentTempOrder = order;
|
||||
this.coilSelectionVisible = true;
|
||||
this.searchCoils();
|
||||
},
|
||||
|
||||
// 计算总重量
|
||||
calculateTotalWeight(coils) {
|
||||
if (!coils || coils.length === 0) return 0;
|
||||
return coils.reduce((total, coil) => {
|
||||
return total + (parseFloat(coil.netWeight) || 0);
|
||||
}, 0);
|
||||
},
|
||||
|
||||
// 计算选中钢卷的总重量
|
||||
calculateSelectedWeight() {
|
||||
return this.calculateTotalWeight(this.selectedCoils);
|
||||
},
|
||||
|
||||
// 查询钢卷
|
||||
async searchCoils() {
|
||||
this.coilLoading = true;
|
||||
try {
|
||||
// 构建查询参数
|
||||
const params = { ...this.coilQueryParams };
|
||||
|
||||
// 移除空值参数
|
||||
Object.keys(params).forEach(key => {
|
||||
if (params[key] === '' || params[key] === null || params[key] === undefined) {
|
||||
delete params[key];
|
||||
}
|
||||
});
|
||||
|
||||
// 调用接口查询钢卷
|
||||
const response = await listMaterialCoil(params);
|
||||
this.availableCoils = response.rows || [];
|
||||
this.coilTotal = response.total || 0;
|
||||
|
||||
// 过滤掉所有单据中已选择的钢卷,确保钢卷在所有单据中唯一
|
||||
const allExistingCoilIds = [];
|
||||
this.tempOrderList.forEach(order => {
|
||||
if (order.coils && Array.isArray(order.coils)) {
|
||||
order.coils.forEach(coil => {
|
||||
if (coil.coilId) {
|
||||
allExistingCoilIds.push(coil.coilId);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 如果是当前正在编辑的单据,排除当前单据中的钢卷(因为它们已经在allExistingCoilIds中了)
|
||||
// 这样可以确保其他单据不能选择当前单据已选的钢卷
|
||||
this.availableCoils = this.availableCoils.filter(coil => !allExistingCoilIds.includes(coil.coilId));
|
||||
|
||||
} catch (error) {
|
||||
console.error('查询钢卷失败:', error);
|
||||
this.$message.error('查询钢卷失败');
|
||||
} finally {
|
||||
this.coilLoading = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 重置钢卷查询条件
|
||||
resetCoilQuery() {
|
||||
this.coilQueryParams = {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
enterCoilNo: '',
|
||||
currentCoilNo: '',
|
||||
itemName: '',
|
||||
itemSpecification: '',
|
||||
itemMaterial: '',
|
||||
status: 0,
|
||||
orderBy: true,
|
||||
dataType: 1,
|
||||
materialType: '成品',
|
||||
itemType: 'product',
|
||||
excludeBound: true,
|
||||
selectType: 'product'
|
||||
};
|
||||
this.searchCoils();
|
||||
},
|
||||
|
||||
// 处理钢卷选择变化
|
||||
handleCoilSelection(selection) {
|
||||
this.selectedCoils = selection;
|
||||
},
|
||||
|
||||
// 保存选中的钢卷
|
||||
saveSelectedCoils() {
|
||||
if (!this.currentTempOrder) {
|
||||
this.$message.error('请先选择暂存单据');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.selectedCoils.length === 0) {
|
||||
this.$message.warning('请选择要添加的钢卷');
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保coils数组存在
|
||||
if (!this.currentTempOrder.coils) {
|
||||
this.currentTempOrder.coils = [];
|
||||
}
|
||||
|
||||
// 由于在查询阶段已经过滤了所有重复的钢卷,这里不需要再次检查
|
||||
// 但为了安全起见,保留基本的检查逻辑
|
||||
if (this.currentTempOrder.coils && this.currentTempOrder.coils.length > 0) {
|
||||
const existingCoilIds = this.currentTempOrder.coils.map(coil => coil.coilId);
|
||||
const duplicateCoils = this.selectedCoils.filter(coil => existingCoilIds.includes(coil.coilId));
|
||||
|
||||
if (duplicateCoils.length > 0) {
|
||||
this.$message.warning(`钢卷 ${duplicateCoils.map(coil => coil.enterCoilNo).join(', ')} 已存在,不能重复添加`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加钢卷到当前单据
|
||||
this.currentTempOrder.coils.push(...this.selectedCoils);
|
||||
this.saveTempOrderList();
|
||||
|
||||
this.$message.success(`成功添加 ${this.selectedCoils.length} 个钢卷`);
|
||||
|
||||
// 关闭对话框并重置选择
|
||||
this.coilSelectionVisible = false;
|
||||
this.selectedCoils = [];
|
||||
},
|
||||
|
||||
// 从单据中移除钢卷
|
||||
removeCoilFromOrder(index) {
|
||||
if (!this.currentTempOrder || !this.currentTempOrder.coils || !this.currentTempOrder.coils[index]) return;
|
||||
|
||||
this.$confirm('确认移除该钢卷吗?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
this.currentTempOrder.coils.splice(index, 1);
|
||||
this.saveTempOrderList();
|
||||
this.$message.success('移除成功');
|
||||
}).catch(() => {
|
||||
this.$message.info('已取消移除');
|
||||
});
|
||||
},
|
||||
|
||||
// 钢卷分页相关方法
|
||||
handleCoilSizeChange(val) {
|
||||
this.coilQueryParams.pageSize = val;
|
||||
this.coilQueryParams.pageNum = 1;
|
||||
this.searchCoils();
|
||||
},
|
||||
|
||||
handleCoilCurrentChange(val) {
|
||||
this.coilQueryParams.pageNum = val;
|
||||
this.searchCoils();
|
||||
},
|
||||
|
||||
// 进入数字钢卷页面
|
||||
handleNumberCoilClick(row) {
|
||||
this.$router.push({
|
||||
|
||||
@@ -47,6 +47,15 @@
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="单据状态" prop="status">
|
||||
<el-select v-model="queryParams.status" placeholder="请选择完成状态" @change="handleQuery">
|
||||
<el-option label="已发货" :value="1" />
|
||||
<el-option label="未发货" :value="0" />
|
||||
<el-option label="已打印" :value="2" />
|
||||
<el-option label="未打印" :value="3" />
|
||||
</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>
|
||||
|
||||
@@ -1,601 +1,392 @@
|
||||
<template>
|
||||
<div class="spec-page">
|
||||
<!-- 规程类型 -->
|
||||
<div class="dict-toolbar-row">
|
||||
<div class="type-tab-bar">
|
||||
<span
|
||||
v-for="t in specTypeTab"
|
||||
:key="'stype-' + (t.value === '' ? 'all' : t.value)"
|
||||
:class="['type-tab', { active: activeSpecType === t.value }]"
|
||||
@click="switchSpecType(t.value)"
|
||||
>{{ t.label }}</span>
|
||||
</div>
|
||||
<dict-select
|
||||
toolbar-only
|
||||
:kisv="false"
|
||||
:editable="true"
|
||||
:refresh="false"
|
||||
:dict-type="DICT_SPEC_TYPE"
|
||||
panel-title="规程工艺类型字典"
|
||||
@dict-updated="loadSpecTypeDict"
|
||||
/>
|
||||
<div class="spec-version-page" v-loading="pageLoading">
|
||||
<!-- 头部 -->
|
||||
<div class="page-header">
|
||||
<span class="page-title">规程版本管理</span>
|
||||
<el-button
|
||||
type="primary"
|
||||
size="small"
|
||||
icon="el-icon-plus"
|
||||
style="margin-left:auto"
|
||||
@click="openSpecDialog()"
|
||||
>新建规程</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 产线 -->
|
||||
<div class="dict-toolbar-row line-row">
|
||||
<div class="line-tab-bar">
|
||||
<span
|
||||
:class="['line-tab', { active: activeLineId === '' }]"
|
||||
@click="switchLine('')"
|
||||
>全部</span>
|
||||
<span
|
||||
v-for="line in lineOptions"
|
||||
:key="'ln-' + line.lineId"
|
||||
:class="['line-tab', { active: lineTabActive(line) }]"
|
||||
@click="switchLine(line.lineId)"
|
||||
>{{ line.lineName }}</span>
|
||||
</div>
|
||||
<dict-select
|
||||
toolbar-only
|
||||
:kisv="false"
|
||||
:editable="true"
|
||||
:refresh="false"
|
||||
:dict-type="DICT_LINE"
|
||||
panel-title="规程产线筛选项(字典值为产线 line_id)"
|
||||
@dict-updated="loadLineOptions"
|
||||
/>
|
||||
<!-- 规程列表 -->
|
||||
<div class="section-wrapper">
|
||||
<div class="section-title">规程列表</div>
|
||||
<el-table
|
||||
:data="specList"
|
||||
size="small"
|
||||
highlight-current-row
|
||||
@row-click="onSpecRowClick"
|
||||
:row-class-name="tableRowClassName"
|
||||
>
|
||||
<el-table-column label="规程编码" prop="specCode" width="150" />
|
||||
<el-table-column label="规程名称" prop="specName" />
|
||||
<el-table-column label="创建时间" prop="createTime" width="180" />
|
||||
<el-table-column label="操作" align="right" width="180">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click.stop="openSpecDialog(row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click.stop="removeSpec(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
|
||||
<!-- 工具栏 -->
|
||||
<div class="toolbar">
|
||||
<div class="toolbar-left">
|
||||
<el-button type="primary" size="mini" icon="el-icon-plus" @click="handleAdd">新增</el-button>
|
||||
<el-button size="mini" icon="el-icon-edit" :disabled="single" @click="handleUpdate()">修改</el-button>
|
||||
<el-button size="mini" icon="el-icon-delete" :disabled="multiple" @click="handleDelete()">删除</el-button>
|
||||
</div>
|
||||
<div class="toolbar-right">
|
||||
<el-input
|
||||
v-model="queryParams.specName"
|
||||
size="small"
|
||||
placeholder="规程名称"
|
||||
clearable
|
||||
style="width:180px; margin-right:8px"
|
||||
@keyup.enter.native="handleQuery"
|
||||
/>
|
||||
<el-button size="mini" type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button size="mini" @click="resetQuery">重置</el-button>
|
||||
<!-- 版本列表 -->
|
||||
<div class="section-wrapper" v-if="currentSpec">
|
||||
<div class="section-title">
|
||||
版本列表 - {{ currentSpec.specName }}
|
||||
<el-button
|
||||
type="primary"
|
||||
size="mini"
|
||||
icon="el-icon-plus"
|
||||
@click="openVersionDialog()"
|
||||
>新建版本</el-button>
|
||||
</div>
|
||||
<el-table
|
||||
:data="versionList"
|
||||
size="small"
|
||||
highlight-current-row
|
||||
@row-click="onVersionRowClick"
|
||||
>
|
||||
<el-table-column label="版本号" prop="versionCode" />
|
||||
<el-table-column label="状态" prop="status" />
|
||||
<el-table-column label="创建时间" prop="createTime" />
|
||||
<el-table-column label="生效" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch
|
||||
:value="row.isActive === 1"
|
||||
active-color="#5F7BA0"
|
||||
@click.native.stop
|
||||
@change="handleActiveChange(row, $event)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click.stop="openVersionDialog(row)">编辑</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click.stop="removeVersion(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-if="!versionList.length && !versionLoading" description="暂无版本,请新建" style="padding:40px 0" />
|
||||
</div>
|
||||
<div v-else class="empty-hint">请选择一个规程查看其版本</div>
|
||||
|
||||
<!-- 列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="dataList"
|
||||
size="small"
|
||||
highlight-current-row
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" />
|
||||
<el-table-column label="规程编号" prop="specCode" show-overflow-tooltip />
|
||||
<el-table-column label="规程名称" prop="specName" show-overflow-tooltip />
|
||||
<el-table-column label="产品类型" prop="productType" show-overflow-tooltip />
|
||||
<el-table-column label="创建时间" prop="createTime" />
|
||||
<el-table-column label="启用" align="center">
|
||||
<template slot-scope="{ row }">
|
||||
<el-switch
|
||||
:value="row.isEnabled === 1"
|
||||
active-color="#5F7BA0"
|
||||
@change="toggleEnabled(row, $event)"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="right">
|
||||
<template slot-scope="{ row }">
|
||||
<el-button type="text" size="mini" @click="goVersionManage(row)">版本与方案</el-button>
|
||||
<el-button type="text" size="mini" @click="handleUpdate(row)">修改</el-button>
|
||||
<el-button type="text" size="mini" class="btn-danger" @click="handleDelete(row)">删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<pagination
|
||||
v-show="total > 0"
|
||||
:total="total"
|
||||
:page.sync="queryParams.pageNum"
|
||||
:limit.sync="queryParams.pageSize"
|
||||
@pagination="getList"
|
||||
/>
|
||||
|
||||
<!-- 新增/修改 -->
|
||||
<el-dialog :title="dialogTitle" :visible.sync="open" width="520px" append-to-body @close="reset">
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="88px" size="small">
|
||||
<el-form-item label="规程编号" prop="specCode">
|
||||
<el-input v-model="form.specCode" placeholder="唯一编号" maxlength="64" show-word-limit />
|
||||
<!-- 新建/编辑规程 -->
|
||||
<el-dialog :title="specTitle" :visible.sync="specOpen" width="500px" append-to-body @close="specForm = {}">
|
||||
<el-form ref="specFormRef" :model="specForm" :rules="specRules" label-width="88px" size="small">
|
||||
<el-form-item label="规程编码" prop="specCode">
|
||||
<el-input v-model="specForm.specCode" placeholder="请输入规程编码" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规程名称" prop="specName">
|
||||
<el-input v-model="form.specName" maxlength="200" show-word-limit />
|
||||
<el-input v-model="specForm.specName" placeholder="请输入规程名称" maxlength="200" />
|
||||
</el-form-item>
|
||||
<el-form-item label="规程类型" prop="specType">
|
||||
<el-select v-model="form.specType" style="width:100%">
|
||||
<el-option
|
||||
v-for="t in specTypeOptionsForForm"
|
||||
:key="t.dictValue"
|
||||
:label="t.dictLabel"
|
||||
:value="t.dictValue"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="产线" prop="lineId">
|
||||
<el-select v-model="form.lineId" filterable placeholder="请选择" style="width:100%">
|
||||
<el-option
|
||||
v-for="line in lineOptionsForForm"
|
||||
:key="line.lineId"
|
||||
:label="lineOptLabel(line)"
|
||||
:value="line.lineId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="产品类型" prop="productType">
|
||||
<el-input v-model="form.productType" maxlength="100" />
|
||||
</el-form-item>
|
||||
<el-form-item label="是否启用" prop="isEnabled">
|
||||
<el-switch v-model="form.isEnabled" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input v-model="form.remark" type="textarea" rows="2" maxlength="500" show-word-limit />
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="specForm.remark" type="textarea" rows="2" maxlength="500" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="small" @click="open = false">取消</el-button>
|
||||
<el-button size="small" type="primary" :loading="btnLoading" @click="submitForm">确定</el-button>
|
||||
<el-button size="small" @click="specOpen = false">取消</el-button>
|
||||
<el-button size="small" type="primary" :loading="specSubmitLoading" @click="submitSpec">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 新建/编辑版本 -->
|
||||
<el-dialog :title="versionTitle" :visible.sync="versionOpen" width="500px" append-to-body @close="versionForm = {}">
|
||||
<el-form ref="versionFormRef" :model="versionForm" :rules="versionRules" label-width="88px" size="small">
|
||||
<el-form-item label="版本号" prop="versionCode">
|
||||
<el-input v-model="versionForm.versionCode" placeholder="如 V1.0" maxlength="64" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态" prop="status">
|
||||
<el-select v-model="versionForm.status" style="width:100%">
|
||||
<el-option v-for="s in statusOptions" :key="s" :label="s" :value="s" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="保存后生效">
|
||||
<el-switch v-model="versionForm.isActive" :active-value="1" :inactive-value="0" />
|
||||
</el-form-item>
|
||||
<el-form-item label="备注">
|
||||
<el-input v-model="versionForm.remark" type="textarea" rows="2" maxlength="500" show-word-limit />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div slot="footer">
|
||||
<el-button size="small" @click="versionOpen = false">取消</el-button>
|
||||
<el-button size="small" type="primary" :loading="versionSubmitLoading" @click="submitVersion">确定</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getDicts } from '@/api/system/dict/data'
|
||||
import { listProcessSpec, getProcessSpec, delProcessSpec, updateProcessSpec, addProcessSpec } from '@/api/wms/processSpec'
|
||||
import { listProductionLine } from '@/api/wms/productionLine'
|
||||
|
||||
const DICT_SPEC_TYPE = 'wms_process_spec_type'
|
||||
const DICT_LINE = 'wms_process_spec_line'
|
||||
|
||||
const DEFAULT_SPEC_TYPES = [
|
||||
]
|
||||
import { listProcessSpec, getProcessSpec, addProcessSpec, updateProcessSpec, delProcessSpec } from '@/api/wms/processSpec'
|
||||
import {
|
||||
listProcessSpecVersion,
|
||||
addProcessSpecVersion,
|
||||
updateProcessSpecVersion,
|
||||
delProcessSpecVersion,
|
||||
activateProcessSpecVersion
|
||||
} from '@/api/wms/processSpecVersion'
|
||||
|
||||
export default {
|
||||
name: 'ProcessSpec',
|
||||
name: 'SpecVersionManage',
|
||||
data() {
|
||||
return {
|
||||
DICT_SPEC_TYPE,
|
||||
DICT_LINE,
|
||||
loading: false,
|
||||
btnLoading: false,
|
||||
total: 0,
|
||||
dataList: [],
|
||||
ids: [],
|
||||
single: true,
|
||||
multiple: true,
|
||||
open: false,
|
||||
dialogTitle: '',
|
||||
specTypeRows: [],
|
||||
lineOptions: [],
|
||||
activeSpecType: '',
|
||||
activeLineId: '',
|
||||
queryParams: {
|
||||
pageNum: 1,
|
||||
pageSize: 20,
|
||||
specName: undefined,
|
||||
specType: undefined,
|
||||
lineId: undefined
|
||||
pageLoading: false,
|
||||
specList: [],
|
||||
currentSpec: null,
|
||||
currentSpecId: null,
|
||||
versionList: [],
|
||||
versionLoading: false,
|
||||
statusOptions: ['DRAFT', 'PUBLISHED', 'OBSOLETE'],
|
||||
|
||||
// 规程相关
|
||||
specOpen: false,
|
||||
specTitle: '',
|
||||
specSubmitLoading: false,
|
||||
specForm: {},
|
||||
specRules: {
|
||||
specCode: [{ required: true, message: '规程编码不能为空', trigger: 'blur' }],
|
||||
specName: [{ required: true, message: '规程名称不能为空', trigger: 'blur' }]
|
||||
},
|
||||
form: {},
|
||||
rules: {
|
||||
specCode: [{ required: true, message: '规程编号不能为空', trigger: 'blur' }],
|
||||
specName: [{ required: true, message: '规程名称不能为空', trigger: 'blur' }],
|
||||
specType: [{ required: true, message: '请选择规程类型', trigger: 'change' }],
|
||||
lineId: [{ required: true, message: '请选择产线', trigger: 'change' }]
|
||||
|
||||
// 版本相关
|
||||
versionOpen: false,
|
||||
versionTitle: '',
|
||||
versionSubmitLoading: false,
|
||||
versionForm: {},
|
||||
versionRules: {
|
||||
versionCode: [{ required: true, message: '版本号不能为空', trigger: 'blur' }],
|
||||
status: [{ required: true, message: '状态不能为空', trigger: 'change' }]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
specTypeTab() {
|
||||
const rows = this.mergeSpecTypeRowsWithDefaults()
|
||||
const sorted = [...rows].sort((a, b) => (Number(a.dictSort) || 0) - (Number(b.dictSort) || 0))
|
||||
return [{ label: '全部', value: '' }, ...sorted.map(r => ({ label: r.dictLabel, value: r.dictValue }))]
|
||||
},
|
||||
specTypeOptionsForForm() {
|
||||
const rows = this.mergeSpecTypeRowsWithDefaults()
|
||||
return [...rows].sort((a, b) => (Number(a.dictSort) || 0) - (Number(b.dictSort) || 0))
|
||||
},
|
||||
lineOptionsForForm() {
|
||||
return this.lineOptions
|
||||
}
|
||||
},
|
||||
created() {
|
||||
Promise.all([this.loadSpecTypeDict(), this.loadLineOptions()]).finally(() => {
|
||||
this.getList()
|
||||
})
|
||||
this.loadSpecs()
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* 工艺类型:默认 PROCESS/STANDARD 与字典合并。若仅有字典中存在的新项,仍可保留两行基础兜底;同 dict_value 以字典为准(可改名、调 sort)。
|
||||
*/
|
||||
mergeSpecTypeRowsWithDefaults() {
|
||||
const byVal = new Map()
|
||||
DEFAULT_SPEC_TYPES.forEach(row => {
|
||||
byVal.set(row.dictValue, { ...row })
|
||||
})
|
||||
for (const row of this.specTypeRows || []) {
|
||||
if (!row || row.dictValue === undefined || row.dictValue === null || row.dictValue === '') continue
|
||||
const v = String(row.dictValue)
|
||||
const prev = byVal.get(v)
|
||||
const sort = row.dictSort != null && row.dictSort !== ''
|
||||
? Number(row.dictSort)
|
||||
: (prev && prev.dictSort != null ? prev.dictSort : 999)
|
||||
const label = (row.dictLabel != null && String(row.dictLabel).trim() !== '')
|
||||
? row.dictLabel
|
||||
: (prev && prev.dictLabel)
|
||||
byVal.set(v, {
|
||||
dictLabel: label,
|
||||
dictValue: v,
|
||||
dictSort: sort
|
||||
})
|
||||
}
|
||||
return Array.from(byVal.values())
|
||||
// 表格行样式
|
||||
tableRowClassName({ row }) {
|
||||
return row.specId === this.currentSpecId ? 'current-row' : ''
|
||||
},
|
||||
/**
|
||||
* 产线 ID 与字典值:用数字字符串,避免超过 Number.MAX_SAFE_INTEGER 时精度丢失(雪花 id)。
|
||||
*/
|
||||
normalizeLineIdString(value) {
|
||||
if (value === undefined || value === null || value === '') return ''
|
||||
const s = String(value).trim()
|
||||
return /^\d+$/.test(s) ? s : ''
|
||||
},
|
||||
/** Tab 高亮:雪花 id 一律按字符串比较 */
|
||||
lineTabActive(line) {
|
||||
if (this.activeLineId === '' || this.activeLineId === undefined) return false
|
||||
return String(this.activeLineId) === String(line.lineId)
|
||||
},
|
||||
parseDictRows(res) {
|
||||
const rows = (res.data || []).filter(d => d.status === '0' || d.status === undefined)
|
||||
rows.sort((a, b) => (Number(a.dictSort) || 0) - (Number(b.dictSort) || 0))
|
||||
return rows
|
||||
},
|
||||
async loadSpecTypeDict() {
|
||||
try {
|
||||
const res = await getDicts(DICT_SPEC_TYPE)
|
||||
this.specTypeRows = this.parseDictRows(res)
|
||||
} catch (err) {
|
||||
console.error('规程工艺类型字典加载失败', err)
|
||||
this.specTypeRows = []
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 产线 Tab:产线主表 ∪ 字典中合法数字 line_id(字典独有也会显示 Tab)。
|
||||
* line_id 全程用数字字符串,避免超过 Number.MAX_SAFE_INTEGER 时精度丢失;字典值须为数字 line_id。
|
||||
*/
|
||||
async loadLineOptions() {
|
||||
const previousOptions = Array.isArray(this.lineOptions) && this.lineOptions.length
|
||||
? this.lineOptions.map(o => ({ ...o }))
|
||||
: []
|
||||
|
||||
let dictRows = []
|
||||
try {
|
||||
const res = await getDicts(DICT_LINE)
|
||||
dictRows = this.parseDictRows(res)
|
||||
} catch (err) {
|
||||
console.error('规程产线字典加载失败', err)
|
||||
}
|
||||
|
||||
const dictMeta = new Map()
|
||||
for (const d of dictRows) {
|
||||
const idStr = this.normalizeLineIdString(d.dictValue)
|
||||
if (!idStr) continue
|
||||
const sort = Number(d.dictSort) || 0
|
||||
const label = (d.dictLabel != null && String(d.dictLabel).trim() !== '')
|
||||
? String(d.dictLabel).trim()
|
||||
: idStr
|
||||
dictMeta.set(idStr, { label, sort })
|
||||
}
|
||||
|
||||
let tableLines = []
|
||||
// try {
|
||||
// const res = await listProductionLine({ pageNum: 1, pageSize: 500 })
|
||||
// tableLines = (res.rows || []).map(p => {
|
||||
// const idStr = this.normalizeLineIdString(p.lineId) || (p.lineId != null ? String(p.lineId).trim() : '')
|
||||
// return {
|
||||
// lineId: idStr,
|
||||
// lineName: p.lineName,
|
||||
// lineCode: p.lineCode
|
||||
// }
|
||||
// }).filter(p => p.lineId)
|
||||
// } catch (e2) {
|
||||
// console.error('产线列表加载失败', e2)
|
||||
// }
|
||||
|
||||
const tableIdSet = new Set(tableLines.map(l => String(l.lineId)))
|
||||
const next = []
|
||||
|
||||
for (const line of tableLines) {
|
||||
const idStr = String(line.lineId)
|
||||
const dm = dictMeta.get(idStr)
|
||||
next.push({
|
||||
lineId: idStr,
|
||||
lineName: dm ? dm.label : line.lineName,
|
||||
lineCode: line.lineCode
|
||||
})
|
||||
}
|
||||
|
||||
const dictOnly = []
|
||||
for (const [idStr, meta] of dictMeta) {
|
||||
if (!tableIdSet.has(idStr)) {
|
||||
dictOnly.push({ lineId: idStr, lineName: meta.label, lineCode: undefined, _sort: meta.sort })
|
||||
|
||||
// 加载规程列表
|
||||
loadSpecs() {
|
||||
this.pageLoading = true
|
||||
listProcessSpec({ pageNum: 1, pageSize: 500 }).then(res => {
|
||||
this.specList = res.rows || []
|
||||
if (this.specList.length > 0 && !this.currentSpec) {
|
||||
this.selectSpec(this.specList[0])
|
||||
}
|
||||
}
|
||||
dictOnly.sort((a, b) => a._sort - b._sort)
|
||||
dictOnly.forEach(d => {
|
||||
const { _sort, ...rest } = d
|
||||
next.push(rest)
|
||||
}).catch(e => console.error(e)).finally(() => { this.pageLoading = false })
|
||||
},
|
||||
|
||||
// 选择规程
|
||||
selectSpec(spec) {
|
||||
this.currentSpec = spec
|
||||
this.currentSpecId = spec.specId
|
||||
this.loadVersions()
|
||||
},
|
||||
|
||||
// 点击规程行
|
||||
onSpecRowClick(row) {
|
||||
this.selectSpec(row)
|
||||
},
|
||||
|
||||
// 加载版本列表
|
||||
loadVersions() {
|
||||
if (!this.currentSpecId) return
|
||||
this.versionLoading = true
|
||||
listProcessSpecVersion({ specId: this.currentSpecId, pageNum: 1, pageSize: 200 }).then(res => {
|
||||
this.versionList = res.rows || []
|
||||
}).catch(e => console.error(e)).finally(() => { this.versionLoading = false })
|
||||
},
|
||||
|
||||
// 点击版本行
|
||||
onVersionRowClick(row) {
|
||||
this.goPlanSpec(row)
|
||||
},
|
||||
|
||||
// 跳转到方案详情
|
||||
goPlanSpec(row) {
|
||||
const basePath = this.$route.path.replace(/\/[^/]*$/, '')
|
||||
console.log(basePath)
|
||||
this.$router.push({
|
||||
path: `/process/processSpec/planSpec`,
|
||||
query: { specId: this.currentSpecId, versionId: String(row.versionId), versionCode: row.versionCode }
|
||||
})
|
||||
|
||||
if (next.length === 0 && previousOptions.length > 0) {
|
||||
console.warn('[规程产线] 本次未解析出有效筛选项(可能字典值非数字或产线接口异常),保留上一版 Tab')
|
||||
},
|
||||
|
||||
// 生效切换
|
||||
handleActiveChange(row, val) {
|
||||
if (!val) {
|
||||
this.$message.info('请激活其他版本来替换当前生效版本')
|
||||
return
|
||||
}
|
||||
this.lineOptions = next
|
||||
},
|
||||
lineOptLabel(line) {
|
||||
if (line.lineCode) {
|
||||
return `${line.lineName}(${line.lineCode})`
|
||||
}
|
||||
return line.lineName
|
||||
},
|
||||
getList() {
|
||||
this.loading = true
|
||||
listProcessSpec(this.queryParams).then(res => {
|
||||
this.dataList = res.rows || []
|
||||
this.total = res.total || 0
|
||||
}).finally(() => { this.loading = false })
|
||||
},
|
||||
switchSpecType(val) {
|
||||
this.activeSpecType = val
|
||||
this.queryParams.specType = val || undefined
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
switchLine(lineId) {
|
||||
if (lineId === '' || lineId === undefined || lineId === null) {
|
||||
this.activeLineId = ''
|
||||
} else {
|
||||
const s = this.normalizeLineIdString(lineId)
|
||||
this.activeLineId = s || String(lineId).trim()
|
||||
}
|
||||
this.queryParams.lineId = this.activeLineId === '' ? undefined : this.activeLineId
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
handleQuery() {
|
||||
this.queryParams.pageNum = 1
|
||||
this.getList()
|
||||
},
|
||||
resetQuery() {
|
||||
this.queryParams.specName = undefined
|
||||
this.handleQuery()
|
||||
},
|
||||
handleSelectionChange(sel) {
|
||||
this.ids = sel.map(r => r.specId)
|
||||
this.single = sel.length !== 1
|
||||
this.multiple = !sel.length
|
||||
},
|
||||
defaultSpecType() {
|
||||
const first = this.specTypeOptionsForForm[0]
|
||||
return first ? first.dictValue : 'PROCESS'
|
||||
},
|
||||
reset() {
|
||||
this.form = {
|
||||
specId: undefined,
|
||||
specCode: undefined,
|
||||
specName: undefined,
|
||||
specType: this.defaultSpecType(),
|
||||
lineId: undefined,
|
||||
productType: undefined,
|
||||
isEnabled: 1,
|
||||
remark: undefined
|
||||
}
|
||||
this.$refs.form && this.$refs.form.clearValidate()
|
||||
},
|
||||
handleAdd() {
|
||||
this.reset()
|
||||
this.dialogTitle = '新增规程'
|
||||
this.open = true
|
||||
},
|
||||
handleUpdate(row) {
|
||||
this.reset()
|
||||
const specId = row ? row.specId : this.ids[0]
|
||||
getProcessSpec(specId).then(res => {
|
||||
this.form = res.data || {}
|
||||
if (this.form.lineId != null && this.form.lineId !== '') {
|
||||
const sid = this.normalizeLineIdString(this.form.lineId)
|
||||
this.form.lineId = sid || String(this.form.lineId).trim()
|
||||
}
|
||||
this.dialogTitle = '修改规程'
|
||||
this.open = true
|
||||
})
|
||||
},
|
||||
submitForm() {
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
this.btnLoading = true
|
||||
const req = this.form.specId ? updateProcessSpec(this.form) : addProcessSpec(this.form)
|
||||
req.then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
this.open = false
|
||||
this.getList()
|
||||
}).finally(() => { this.btnLoading = false })
|
||||
})
|
||||
},
|
||||
handleDelete(row) {
|
||||
const ids = row ? row.specId : this.ids
|
||||
this.$modal.confirm('确认删除所选规程?').then(() => {
|
||||
this.loading = true
|
||||
return delProcessSpec(ids)
|
||||
this.$modal.confirm('确认将版本"' + row.versionCode + '"设为当前生效版本?').then(() => {
|
||||
return activateProcessSpecVersion(row.versionId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
this.getList()
|
||||
}).catch(() => {}).finally(() => { this.loading = false })
|
||||
},
|
||||
toggleEnabled(row, val) {
|
||||
const updated = { ...row, isEnabled: val ? 1 : 0 }
|
||||
updateProcessSpec(updated).then(() => {
|
||||
row.isEnabled = updated.isEnabled
|
||||
this.$modal.msgSuccess('已生效')
|
||||
this.loadVersions()
|
||||
}).catch(() => {})
|
||||
},
|
||||
goVersionManage(row) {
|
||||
const pathCurrent = this.$route.path.replace(/\/$/, '')
|
||||
const m = pathCurrent.match(/^(.*\/processSpec)(?:\/.*)?$/)
|
||||
const base = m ? m[1] : pathCurrent
|
||||
this.$router.push({ path: `${base}/version`, query: { specId: String(row.specId) } })
|
||||
|
||||
// 规程对话框
|
||||
openSpecDialog(row) {
|
||||
this.specForm = row
|
||||
? { ...row }
|
||||
: { specCode: undefined, specName: undefined, remark: undefined }
|
||||
this.specTitle = row ? '编辑规程' : '新建规程'
|
||||
this.specOpen = true
|
||||
this.$nextTick(() => this.$refs.specFormRef && this.$refs.specFormRef.clearValidate())
|
||||
},
|
||||
|
||||
// 提交规程
|
||||
submitSpec() {
|
||||
this.$refs.specFormRef.validate(ok => {
|
||||
if (!ok) return
|
||||
this.specSubmitLoading = true
|
||||
const req = this.specForm.specId ? updateProcessSpec(this.specForm) : addProcessSpec(this.specForm)
|
||||
req.then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
this.specOpen = false
|
||||
this.loadSpecs()
|
||||
}).catch(e => console.error(e)).finally(() => { this.specSubmitLoading = false })
|
||||
})
|
||||
},
|
||||
|
||||
// 删除规程
|
||||
removeSpec(row) {
|
||||
this.$modal.confirm('确认删除规程"' + row.specName + '"?').then(() => {
|
||||
return delProcessSpec(row.specId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
if (this.currentSpecId === row.specId) {
|
||||
this.currentSpec = null
|
||||
this.currentSpecId = null
|
||||
this.versionList = []
|
||||
}
|
||||
this.loadSpecs()
|
||||
}).catch(() => {})
|
||||
},
|
||||
|
||||
// 版本对话框
|
||||
openVersionDialog(row) {
|
||||
this.versionForm = row
|
||||
? { ...row }
|
||||
: { specId: this.currentSpecId, versionCode: undefined, status: 'DRAFT', isActive: 0, remark: undefined }
|
||||
this.versionTitle = row ? '编辑版本' : '新建版本'
|
||||
this.versionOpen = true
|
||||
this.$nextTick(() => this.$refs.versionFormRef && this.$refs.versionFormRef.clearValidate())
|
||||
},
|
||||
|
||||
// 提交版本
|
||||
submitVersion() {
|
||||
this.$refs.versionFormRef.validate(ok => {
|
||||
if (!ok) return
|
||||
this.versionSubmitLoading = true
|
||||
const req = this.versionForm.versionId
|
||||
? updateProcessSpecVersion({ ...this.versionForm, specId: this.currentSpecId })
|
||||
: addProcessSpecVersion({ ...this.versionForm, specId: this.currentSpecId })
|
||||
req.then(() => {
|
||||
this.$modal.msgSuccess('保存成功')
|
||||
this.versionOpen = false
|
||||
this.loadVersions()
|
||||
}).catch(e => console.error(e)).finally(() => { this.versionSubmitLoading = false })
|
||||
})
|
||||
},
|
||||
|
||||
// 删除版本
|
||||
removeVersion(row) {
|
||||
this.$modal.confirm('确认删除版本"' + row.versionCode + '"?').then(() => {
|
||||
return delProcessSpecVersion(row.versionId)
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess('删除成功')
|
||||
this.loadVersions()
|
||||
}).catch(() => {})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.spec-page {
|
||||
.spec-version-page {
|
||||
padding: 16px 20px;
|
||||
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
/* ── 双色主题:默认=白底灰边,激活/主操作=深藏青 #5F7BA0 ── */
|
||||
|
||||
.dict-toolbar-row {
|
||||
.page-header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
gap: 8px 10px;
|
||||
margin-bottom: 6px;
|
||||
gap: 10px;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.dict-toolbar-row.line-row {
|
||||
.page-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.section-wrapper {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ebeef5;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: #606266;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.type-tab-bar {
|
||||
display: flex;
|
||||
flex: 0 1 auto;
|
||||
flex-wrap: wrap;
|
||||
gap: 0;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
|
||||
.type-tab {
|
||||
padding: 5px 14px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
background: #fff;
|
||||
border: none;
|
||||
border-right: 1px solid #dcdfe6;
|
||||
transition: color .15s, background .15s;
|
||||
user-select: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.type-tab:last-child { border-right: none; }
|
||||
.type-tab:hover { color: #5F7BA0; }
|
||||
|
||||
.type-tab.active {
|
||||
color: #fff;
|
||||
background: #5F7BA0;
|
||||
}
|
||||
|
||||
.line-tab-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex: 0 1 auto;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.line-tab {
|
||||
padding: 4px 12px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
cursor: pointer;
|
||||
color: #606266;
|
||||
background: #fff;
|
||||
border: 1px solid #dcdfe6;
|
||||
transition: color .15s, background .15s, border-color .15s;
|
||||
user-select: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.line-tab:hover { color: #5F7BA0; border-color: #5F7BA0; }
|
||||
|
||||
.line-tab.active {
|
||||
color: #fff;
|
||||
background: #5F7BA0;
|
||||
border-color: #5F7BA0;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.toolbar-left,
|
||||
.toolbar-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
.empty-hint {
|
||||
text-align: center;
|
||||
padding: 60px 0;
|
||||
color: #909399;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.el-table {
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
::v-deep .el-table .current-row {
|
||||
background: #f0f7ff !important;
|
||||
}
|
||||
|
||||
/* el-button:主操作类 → 深藏青;默认类 → 白底灰边 */
|
||||
::v-deep .el-button--primary {
|
||||
color: #fff !important;
|
||||
background: #5F7BA0 !important;
|
||||
border-color: #5F7BA0 !important;
|
||||
}
|
||||
::v-deep .el-button--primary:hover,
|
||||
::v-deep .el-button--primary:focus {
|
||||
background: #4d6a8e !important;
|
||||
border-color: #4d6a8e !important;
|
||||
}
|
||||
::v-deep .el-button--primary:focus { background: #4d6a8e !important; border-color: #4d6a8e !important; }
|
||||
::v-deep .el-button--primary:active { background: #4a6585 !important; border-color: #4a6585 !important; }
|
||||
::v-deep .el-button--primary.is-disabled { opacity: .5; }
|
||||
|
||||
::v-deep .el-button:not(.el-button--primary):not(.el-button--text):not(.el-button--danger):not(.el-button--info) {
|
||||
::v-deep .el-button:not(.el-button--primary):not(.el-button--text):not(.el-button--danger) {
|
||||
color: #606266 !important;
|
||||
background: #fff !important;
|
||||
border-color: #dcdfe6 !important;
|
||||
}
|
||||
::v-deep .el-button:not(.el-button--primary):not(.el-button--text):not(.el-button--danger):not(.el-button--info):hover {
|
||||
::v-deep .el-button:not(.el-button--primary):not(.el-button--text):not(.el-button--danger):hover {
|
||||
color: #5F7BA0 !important;
|
||||
border-color: #5F7BA0 !important;
|
||||
}
|
||||
::v-deep .el-button:not(.el-button--primary):not(.el-button--text):not(.el-button--danger):not(.el-button--info).is-disabled { opacity: .5; }
|
||||
|
||||
::v-deep .el-button--text { background: transparent !important; border-color: transparent !important; }
|
||||
::v-deep .el-button--text.btn-danger { color: #f56c6c !important; }
|
||||
|
||||
.btn-danger { color: #f56c6c; }
|
||||
|
||||
/* 与 Tab 同一行时,将齿轮框配色贴近规程主题 */
|
||||
::v-deep .dict-toolbar-row .el-icon-setting {
|
||||
color: #5F7BA0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
</el-dialog>
|
||||
|
||||
<!-- 模板导入 dialog -->
|
||||
<el-dialog title="模板导入" :visible.sync="importOpen" width="800px" append-to-body @close="resetImport">
|
||||
<el-dialog title="模板导入" :visible.sync="importOpen" width="800px" append-to-body>
|
||||
<div class="import-container">
|
||||
<!-- 文件上传区域 -->
|
||||
<div class="file-upload-area" :class="{ disabled: importStatus === 'processing' }">
|
||||
|
||||
@@ -466,6 +466,7 @@ export default {
|
||||
const res = await listPendingAction({ ...this.queryParams, actionType: this.actionType, actionStatus: 2 });
|
||||
// 获取两层数据
|
||||
const lossIds = res.rows.filter(item => item.coilId).map(item => item.coilId);
|
||||
const lossActionIds = res.rows.filter(item => item.actionId).map(item => item.actionId);
|
||||
// 使用new Set去重
|
||||
const outIds = [...new Set(res.rows.filter(item => item.processedCoilIds).map(item => item.processedCoilIds))];
|
||||
|
||||
@@ -479,7 +480,7 @@ export default {
|
||||
}
|
||||
|
||||
const [lossRes, outRes] = await Promise.all([
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: lossIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
listCoilWithIds({ ...this.queryParams, actionIds: lossActionIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
]);
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ export default {
|
||||
const res = await listPendingAction({ ...this.queryParams, actionType: this.actionType, actionStatus: 2 });
|
||||
// 获取两层数据
|
||||
const lossIds = res.rows.map(item => item.coilId);
|
||||
const lossActionIds = res.rows.map(item => item.actionId);
|
||||
// 使用new Set去重
|
||||
const outIds = [...new Set(res.rows.map(item => item.processedCoilIds))];
|
||||
|
||||
@@ -253,7 +254,7 @@ export default {
|
||||
}
|
||||
|
||||
const [lossRes, outRes] = await Promise.all([
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: lossIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
listCoilWithIds({ ...this.queryParams, actionIds: lossActionIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
listCoilWithIds({ ...this.queryParams, coilIds: outIds.join(',') || '', startTime: '', endTime: '' }),
|
||||
]);
|
||||
this.lossList = lossRes.rows.map(item => {
|
||||
|
||||
Reference in New Issue
Block a user