|
@@ -90,14 +90,14 @@
|
|
|
fixed="left"
|
|
|
/>
|
|
|
<el-table-column :label="t('bomList.bomNode')" align="center" prop="bomNodeId" v-if="false"/>
|
|
|
- <el-table-column :label="t('iotDevice.code')" align="center" prop="deviceCode" :width="columnWidths.deviceCode" fixed="left">
|
|
|
+ <el-table-column :label="t('iotDevice.code')" align="center" prop="deviceCode" v-if="false">
|
|
|
<template #default="{ row }">
|
|
|
<div class="full-content-cell"> <!-- 自定义样式 -->
|
|
|
{{ row.deviceCode }}
|
|
|
</div>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column :label="t('iotDevice.name')" align="center" prop="deviceName" :width="columnWidths.deviceName" fixed="left">
|
|
|
+ <el-table-column :label="t('iotDevice.name')" align="center" prop="deviceName" v-if="false">
|
|
|
<template #default="{ row }">
|
|
|
<div class="full-content-cell"> <!-- 自定义样式 -->
|
|
|
{{ row.deviceName }}
|
|
@@ -107,9 +107,16 @@
|
|
|
<el-table-column :label="t('mainPlan.MaintItems')" align="center" prop="name"
|
|
|
:show-overflow-tooltip="false" :width="columnWidths.name" fixed="left">
|
|
|
<template #default="{ row }">
|
|
|
- <div class="full-content-cell"> <!-- 自定义样式 -->
|
|
|
- {{ row.name }}
|
|
|
- </div>
|
|
|
+ <el-tooltip
|
|
|
+ effect="dark"
|
|
|
+ :content="`设备编码:${row.deviceCode}\n设备名称:${row.deviceName}`"
|
|
|
+ placement="top"
|
|
|
+ popper-class="custom-tooltip"
|
|
|
+ >
|
|
|
+ <div class="full-content-cell"> <!-- 自定义样式 -->
|
|
|
+ {{ row.name }}
|
|
|
+ </div>
|
|
|
+ </el-tooltip>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
<el-table-column :label="t('main.mileage')" key="mileageRule" align="center"
|
|
@@ -354,6 +361,51 @@
|
|
|
</div>
|
|
|
</ContentWrap>
|
|
|
|
|
|
+ <ContentWrap v-show="showMaterialBill">
|
|
|
+ <el-table
|
|
|
+ :data="materialBills"
|
|
|
+ :stripe="true"
|
|
|
+ :row-class-name="tableRowClassName"
|
|
|
+ border
|
|
|
+ >
|
|
|
+ <el-table-column type="index" :label="t('maintain.serial')" align="center" width="60" />
|
|
|
+ <el-table-column label="工厂" align="center" prop="factory">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.factory || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="成本中心" align="center" prop="costCenter">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.costCenter || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="物料编码" align="center" prop="code" >
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span :class="{ 'red-text': !row.factory || !row.costCenter }">
|
|
|
+ {{ row.code }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="物料名称" align="center" prop="name" >
|
|
|
+ <template #default="{ row }">
|
|
|
+ <span :class="{ 'red-text': !row.factory || !row.costCenter }">
|
|
|
+ {{ row.name }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="库存数量" align="center" prop="stockQuantity">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.stockQuantity ?? '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="BOM物料数量" align="center" prop="quantity">
|
|
|
+ <template #default="{ row }">
|
|
|
+ {{ row.quantity ?? '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </ContentWrap>
|
|
|
+
|
|
|
<!-- 选择的物料列表 -->
|
|
|
<ContentWrap>
|
|
|
<el-table v-loading="false" :data="materialList" :stripe="true" :show-overflow-tooltip="true" v-if="false">
|
|
@@ -372,16 +424,26 @@
|
|
|
<el-table-column label="总库存数量" align="center" prop="totalInventoryQuantity" />
|
|
|
</el-table>
|
|
|
</ContentWrap>
|
|
|
-
|
|
|
</ContentWrap>
|
|
|
+
|
|
|
<ContentWrap>
|
|
|
<el-form>
|
|
|
+ <el-form-item style="float: left">
|
|
|
+ <el-button
|
|
|
+ type="primary"
|
|
|
+ @click="toggleMaterialBill"
|
|
|
+ style="margin-bottom: 10px;"
|
|
|
+ >
|
|
|
+ {{ showMaterialBill ? '隐藏物料清单' : '显示物料清单' }}
|
|
|
+ </el-button>
|
|
|
+ </el-form-item>
|
|
|
<el-form-item style="float: right">
|
|
|
<el-button @click="submitForm" type="primary" :disabled="formLoading">{{t('common.save')}}</el-button>
|
|
|
<el-button @click="close">{{t('common.cancel')}}</el-button>
|
|
|
</el-form-item>
|
|
|
</el-form>
|
|
|
</ContentWrap>
|
|
|
+
|
|
|
<!-- 新增配置对话框 -->
|
|
|
<el-dialog
|
|
|
v-model="configDialog.visible"
|
|
@@ -611,6 +673,7 @@
|
|
|
<el-button type="primary" @click="saveConfig">{{ t('common.ok')}}</el-button>
|
|
|
</template>
|
|
|
</el-dialog>
|
|
|
+
|
|
|
<!-- 表单弹窗:添加/修改 -->
|
|
|
<WorkOrderMaterial ref="materialFormRef" @choose="selectChoose" />
|
|
|
<!-- 设备BOM节点绑定的物料列表 -->
|
|
@@ -685,6 +748,9 @@ const lastNaturalDateWatchers = ref(new Map())
|
|
|
|
|
|
const columnWidths = ref<Record<string, string>>({});
|
|
|
|
|
|
+const showMaterialBill = ref(false); // 控制物料清单显示
|
|
|
+const materialBills = ref<any[]>([]); // 物料清单数据
|
|
|
+
|
|
|
const formData = ref({
|
|
|
id: undefined,
|
|
|
deptId: undefined,
|
|
@@ -804,6 +870,33 @@ const configDialog = reactive({
|
|
|
}
|
|
|
})
|
|
|
|
|
|
+// 生成物料清单数据
|
|
|
+const generateMaterialBills = () => {
|
|
|
+ materialBills.value = [];
|
|
|
+
|
|
|
+ list.value.forEach(item => {
|
|
|
+ if (item.deviceBomMaterials && item.deviceBomMaterials.length > 0) {
|
|
|
+ item.deviceBomMaterials.forEach((material: any) => {
|
|
|
+ materialBills.value.push({
|
|
|
+ ...material,
|
|
|
+ // 添加bomNodeId用于跟踪来源
|
|
|
+ bomNodeId: item.bomNodeId
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+// 切换物料清单显示状态
|
|
|
+const toggleMaterialBill = () => {
|
|
|
+ showMaterialBill.value = !showMaterialBill.value;
|
|
|
+
|
|
|
+ // 当显示时生成物料清单数据
|
|
|
+ if (showMaterialBill.value && materialBills.value.length === 0) {
|
|
|
+ generateMaterialBills();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 打开配置对话框
|
|
|
const openConfigDialog = (row: IotMainWorkOrderBomVO) => {
|
|
|
configDialog.current = row
|
|
@@ -1334,8 +1427,8 @@ const calculateAllColumnsWidth = () => {
|
|
|
// 需要自适应的列配置
|
|
|
const autoColumns = [
|
|
|
{ prop: 'serial', label: t('iotDevice.serial') },
|
|
|
- { prop: 'deviceCode', label: t('iotMaintain.deviceCode') },
|
|
|
- { prop: 'deviceName', label: t('iotMaintain.deviceName') },
|
|
|
+ /* { prop: 'deviceCode', label: t('iotMaintain.deviceCode') },
|
|
|
+ { prop: 'deviceName', label: t('iotMaintain.deviceName') }, */
|
|
|
{
|
|
|
prop: 'totalRunTime',
|
|
|
label: t('operationFillForm.sumTime'),
|
|
@@ -1407,7 +1500,7 @@ const calculateAllColumnsWidth = () => {
|
|
|
});
|
|
|
|
|
|
// 固定列特殊处理 - 增加额外空间
|
|
|
- ['serial', 'deviceCode', 'deviceName', 'name'].forEach(prop => {
|
|
|
+ ['serial', 'name'].forEach(prop => {
|
|
|
if (newWidths[prop]) {
|
|
|
newWidths[prop] += FIXED_COLUMN_PADDING;
|
|
|
}
|
|
@@ -1598,9 +1691,68 @@ onMounted(async () => {
|
|
|
formData.value = workOrder
|
|
|
// 查询保养工单 明细数据
|
|
|
const data = await IotMainWorkOrderBomApi.getWorkOrderBOMs(queryParams);
|
|
|
+
|
|
|
+ // 查询当前保养工单已经关联的所有物料
|
|
|
+ const materials = await IotMainWorkOrderBomMaterialApi.getWorkOrderBomMaterials(queryParams);
|
|
|
+ const tobeBoundedMaterials = data.flatMap(item =>
|
|
|
+ item.deviceBomMaterials?.map(mat => ({
|
|
|
+ ...mat,
|
|
|
+ bomNodeId: item.bomNodeId // 确保bomNodeId关联
|
|
|
+ })) || []
|
|
|
+ ).filter(Boolean);
|
|
|
+
|
|
|
+ // 创建唯一键生成函数
|
|
|
+ const getMaterialKey = (mat: any) => {
|
|
|
+ return `${mat.factoryId}_${mat.costCenterId}_${mat.bomNodeId}_${mat.materialCode}`;
|
|
|
+ };
|
|
|
+
|
|
|
+ // 创建合并映射表
|
|
|
+ const materialMap = new Map<string, any>();
|
|
|
+
|
|
|
+ // 先添加接口A的物料(优先级高)
|
|
|
+ materials.forEach(mat => {
|
|
|
+ if (mat.factoryId && mat.costCenterId) { // 基础校验
|
|
|
+ const key = getMaterialKey(mat);
|
|
|
+ materialMap.set(key, {
|
|
|
+ ...mat,
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 5. 再添加接口B的物料(仅添加不存在的)
|
|
|
+ tobeBoundedMaterials.forEach(mat => {
|
|
|
+ if (!mat.factory || !mat.costCenter) {
|
|
|
+ console.warn(`物料${mat.code}缺少工厂或成本中心信息,已跳过`);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 字段映射转换
|
|
|
+ const mappedMat = {
|
|
|
+ ...mat,
|
|
|
+ materialCode: mat.code,
|
|
|
+ materialName: mat.name,
|
|
|
+ totalInventoryQuantity: mat.stockQuantity,
|
|
|
+ materialSource: '本地库存',
|
|
|
+ // 保留原始字段用于后续验证
|
|
|
+ factory: mat.factory,
|
|
|
+ costCenter: mat.costCenter
|
|
|
+ };
|
|
|
+
|
|
|
+ const key = getMaterialKey(mappedMat);
|
|
|
+
|
|
|
+ // 仅当不存在时才添加
|
|
|
+ if (!materialMap.has(key)) {
|
|
|
+ materialMap.set(key, mappedMat);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将映射表转为数组
|
|
|
+ materialList.value = Array.from(materialMap.values());
|
|
|
+
|
|
|
list.value = []
|
|
|
if (Array.isArray(data)) {
|
|
|
list.value = data.map(item => {
|
|
|
+
|
|
|
if (item.mileageRule === 0) {
|
|
|
item.nextMaintenanceKm = calculateNextMaintenanceKm(item);
|
|
|
item.remainKm = calculateRemainKm(item);
|
|
@@ -1620,15 +1772,7 @@ onMounted(async () => {
|
|
|
}
|
|
|
})
|
|
|
}
|
|
|
- // 查询当前保养工单已经关联的所有物料
|
|
|
- const materials = await IotMainWorkOrderBomMaterialApi.getWorkOrderBomMaterials(queryParams);
|
|
|
- materialList.value = []
|
|
|
- if (Array.isArray(materials)) {
|
|
|
- materialList.value = materials
|
|
|
- .map(item => ({
|
|
|
- ...item,
|
|
|
- }))
|
|
|
- }
|
|
|
+
|
|
|
} catch (error) {
|
|
|
console.error('数据加载失败:', error)
|
|
|
message.error('数据加载失败,请重试')
|
|
@@ -1683,6 +1827,11 @@ onUnmounted(async () => {
|
|
|
margin-top: 5px;
|
|
|
}
|
|
|
|
|
|
+/* 确保表格填满容器 */
|
|
|
+:deep(.el-table) {
|
|
|
+ width: 100% !important;
|
|
|
+}
|
|
|
+
|
|
|
:deep(.el-table__body) {
|
|
|
.el-table__cell {
|
|
|
.cell {
|
|
@@ -1719,4 +1868,28 @@ onUnmounted(async () => {
|
|
|
:deep(.el-table__header .el-table__cell:not(.is-group)) {
|
|
|
border-top: 1px solid #dcdfe6 !important; /* 添加顶部边框连接分组标题 */
|
|
|
}
|
|
|
+
|
|
|
+/* Tooltip样式 */
|
|
|
+:deep(.custom-tooltip) {
|
|
|
+ white-space: pre-line;
|
|
|
+ line-height: 1.5;
|
|
|
+ text-align: left;
|
|
|
+ max-width: 300px;
|
|
|
+ background-color: #333;
|
|
|
+ color: #fff;
|
|
|
+ padding: 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
|
|
+}
|
|
|
+
|
|
|
+/* 添加淡红色行样式 */
|
|
|
+:deep(.el-table .warning-row) {
|
|
|
+ background-color: #fff6f6;
|
|
|
+}
|
|
|
+
|
|
|
+.red-text {
|
|
|
+ color: red;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
</style>
|