|
|
|
@ -3,6 +3,36 @@
|
|
|
|
<div class="table-header">
|
|
|
|
<div class="table-header">
|
|
|
|
<h3>实时库存表</h3>
|
|
|
|
<h3>实时库存表</h3>
|
|
|
|
<div class="table-actions">
|
|
|
|
<div class="table-actions">
|
|
|
|
|
|
|
|
<div style="display: flex; align-items: center; margin-right: 15px;">
|
|
|
|
|
|
|
|
<span style="margin-right: 5px;">机台筛选:</span>
|
|
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
|
|
v-model="equipmentFilter"
|
|
|
|
|
|
|
|
placeholder="选择机台"
|
|
|
|
|
|
|
|
style="width: 150px;"
|
|
|
|
|
|
|
|
@change="handleEquipmentFilterChange"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<el-option label="全部机台" value="all" />
|
|
|
|
|
|
|
|
<el-option
|
|
|
|
|
|
|
|
v-for="equipment in equipmentFilterOptions"
|
|
|
|
|
|
|
|
:key="equipment"
|
|
|
|
|
|
|
|
:label="equipment"
|
|
|
|
|
|
|
|
:value="equipment"
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div style="display: flex; align-items: center; margin-right: 15px;">
|
|
|
|
|
|
|
|
<span style="margin-right: 5px;">库存增减:</span>
|
|
|
|
|
|
|
|
<el-select
|
|
|
|
|
|
|
|
v-model="inventoryFilter"
|
|
|
|
|
|
|
|
placeholder="选择筛选条件"
|
|
|
|
|
|
|
|
style="width: 120px;"
|
|
|
|
|
|
|
|
@change="handleFilterChange"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<el-option label="全部" value="all" />
|
|
|
|
|
|
|
|
<el-option label="库存增加" value="increase" />
|
|
|
|
|
|
|
|
<el-option label="库存减少" value="decrease" />
|
|
|
|
|
|
|
|
</el-select>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<el-switch
|
|
|
|
<el-switch
|
|
|
|
v-model="showDifference"
|
|
|
|
v-model="showDifference"
|
|
|
|
active-text="显示库存变化"
|
|
|
|
active-text="显示库存变化"
|
|
|
|
@ -27,6 +57,8 @@
|
|
|
|
:header-cell-style="{ backgroundColor: '#f5f7fa', color: '#606266' }"
|
|
|
|
:header-cell-style="{ backgroundColor: '#f5f7fa', color: '#606266' }"
|
|
|
|
empty-text="暂无数据"
|
|
|
|
empty-text="暂无数据"
|
|
|
|
:scrollbar-always-on="true"
|
|
|
|
:scrollbar-always-on="true"
|
|
|
|
|
|
|
|
height="1000"
|
|
|
|
|
|
|
|
:max-height="1000"
|
|
|
|
@cell-click="handleCellClick"
|
|
|
|
@cell-click="handleCellClick"
|
|
|
|
@cell-dblclick="handleCellDblClick"
|
|
|
|
@cell-dblclick="handleCellDblClick"
|
|
|
|
>
|
|
|
|
>
|
|
|
|
@ -88,6 +120,20 @@
|
|
|
|
}"
|
|
|
|
}"
|
|
|
|
></span>
|
|
|
|
></span>
|
|
|
|
</span>
|
|
|
|
</span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 转移概率数据显示 -->
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
|
|
v-if="getCellTransitionProbabilityData(scope.row.specification, column.prop)"
|
|
|
|
|
|
|
|
class="transition-probability-data"
|
|
|
|
|
|
|
|
style="margin-top: 4px; padding: 4px; border-radius: 3px; font-size: 11px;"
|
|
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
|
|
backgroundColor: getProbabilityColorForDisplay(getCellTransitionProbabilityData(scope.row.specification, column.prop).probability, scope.row.specification, column.prop),
|
|
|
|
|
|
|
|
color: '#000000',
|
|
|
|
|
|
|
|
fontWeight: 'bold'
|
|
|
|
|
|
|
|
}"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
{{ getCellTransitionProbabilityData(scope.row.specification, column.prop).displayText }}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
<template #header>
|
|
|
|
<template #header>
|
|
|
|
@ -126,6 +172,58 @@
|
|
|
|
@data-loaded="onWmsDataLoaded"
|
|
|
|
@data-loaded="onWmsDataLoaded"
|
|
|
|
/>
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 转移概率表格 -->
|
|
|
|
|
|
|
|
<div v-if="currentDialogTransitionData && currentDialogTransitionData.current_specification_transitions" class="transition-probability-section" style="margin-top: 20px;">
|
|
|
|
|
|
|
|
<div class="section-header">
|
|
|
|
|
|
|
|
<h4>转移概率分析 - {{ currentWmsModel }} - {{ currentWmsSpecification }}</h4>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div class="transition-info" style="margin-bottom: 15px; padding: 10px; background-color: #f5f7fa; border-radius: 4px; font-size: 14px;">
|
|
|
|
|
|
|
|
<div v-if="currentDialogTransitionData.input_parameters">
|
|
|
|
|
|
|
|
<strong>输入参数:</strong>
|
|
|
|
|
|
|
|
设备: {{ currentDialogTransitionData.input_parameters.equipment_code }} |
|
|
|
|
|
|
|
|
轴数: {{ currentDialogTransitionData.input_parameters.axle_number }} |
|
|
|
|
|
|
|
|
当前规格: {{ currentDialogTransitionData.input_parameters.specification }}
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div v-if="currentDialogTransitionData.prediction" style="margin-top: 5px;">
|
|
|
|
|
|
|
|
<strong>预测:</strong>
|
|
|
|
|
|
|
|
最可能转移至: {{ currentDialogTransitionData.prediction.most_likely_next_spec }}
|
|
|
|
|
|
|
|
({{ (currentDialogTransitionData.prediction.probability * 100).toFixed(1) }}%)
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<el-table
|
|
|
|
|
|
|
|
:data="getTransitionProbabilityTableData()"
|
|
|
|
|
|
|
|
style="width: 100%; margin-top: 10px;"
|
|
|
|
|
|
|
|
border
|
|
|
|
|
|
|
|
size="small"
|
|
|
|
|
|
|
|
>
|
|
|
|
|
|
|
|
<el-table-column prop="targetSpec" label="目标规格" width="100" />
|
|
|
|
|
|
|
|
<el-table-column prop="probability" label="转移概率" width="120">
|
|
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
|
|
<span>{{ (scope.row.probability * 100).toFixed(1) }}%</span>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
<el-table-column prop="count" label="历史次数" width="100" />
|
|
|
|
|
|
|
|
<el-table-column prop="percentage" label="占比" width="150">
|
|
|
|
|
|
|
|
<template #default="scope">
|
|
|
|
|
|
|
|
<div style="display: flex; align-items: center;">
|
|
|
|
|
|
|
|
<div
|
|
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
|
|
width: (scope.row.probability * 100).toFixed(1) + '%',
|
|
|
|
|
|
|
|
height: '20px',
|
|
|
|
|
|
|
|
backgroundColor: getProbabilityColor(scope.row.probability, '#409EFF'),
|
|
|
|
|
|
|
|
marginRight: '8px',
|
|
|
|
|
|
|
|
borderRadius: '2px'
|
|
|
|
|
|
|
|
}"
|
|
|
|
|
|
|
|
></div>
|
|
|
|
|
|
|
|
<span>{{ (scope.row.probability * 100).toFixed(1) }}%</span>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
</el-table-column>
|
|
|
|
|
|
|
|
</el-table>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 库存历史图表 -->
|
|
|
|
<!-- 库存历史图表 -->
|
|
|
|
<div v-if="wmsDialogVisible" class="inventory-chart-section">
|
|
|
|
<div v-if="wmsDialogVisible" class="inventory-chart-section">
|
|
|
|
<div class="chart-header">
|
|
|
|
<div class="chart-header">
|
|
|
|
@ -154,6 +252,7 @@
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div v-show="!historyChartLoading && hasHistoryData" ref="inventoryChartRef" class="chart" style="height: 450px;"></div>
|
|
|
|
<div v-show="!historyChartLoading && hasHistoryData" ref="inventoryChartRef" class="chart" style="height: 450px;"></div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
</el-dialog>
|
|
|
|
</el-dialog>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
@ -179,11 +278,102 @@ const equipmentCodeColors = ref(new Map()) // equipment_code到颜色的映射
|
|
|
|
// 转移概率数据
|
|
|
|
// 转移概率数据
|
|
|
|
const transitionProbabilitiesMap = ref(new Map()) // 存储转移概率数据
|
|
|
|
const transitionProbabilitiesMap = ref(new Map()) // 存储转移概率数据
|
|
|
|
const transitionColorsMap = ref(new Map()) // 存储概率颜色映射
|
|
|
|
const transitionColorsMap = ref(new Map()) // 存储概率颜色映射
|
|
|
|
|
|
|
|
const activeCells = ref(new Set()) // 存储当前激活的单元格键值
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 事件防抖相关
|
|
|
|
|
|
|
|
let clickTimeoutId = null; // 单击事件延时器
|
|
|
|
|
|
|
|
const DBL_CLICK_DELAY = 250; // 双击延时(毫秒)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 库存筛选相关
|
|
|
|
|
|
|
|
const inventoryFilter = ref('all'); // 筛选类型:all-全部,increase-库存增加,decrease-库存减少
|
|
|
|
|
|
|
|
const equipmentFilter = ref('all'); // 机台筛选:all-全部,具体的equipment_code
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 机台筛选选项
|
|
|
|
|
|
|
|
const equipmentFilterOptions = ref([]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:根据筛选条件获取过滤后的记录
|
|
|
|
|
|
|
|
const getFilteredRecords = (inputRecords = null) => {
|
|
|
|
|
|
|
|
const sourceRecords = inputRecords || records.value;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!sourceRecords.length) {
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (inventoryFilter.value) {
|
|
|
|
|
|
|
|
case 'increase':
|
|
|
|
|
|
|
|
// 库存增加:基于差值数据筛选出有正差值的记录
|
|
|
|
|
|
|
|
if (!differenceRecords.value.length) {
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const increaseKeys = new Set(
|
|
|
|
|
|
|
|
differenceRecords.value
|
|
|
|
|
|
|
|
.filter(diff => diff.difference > 0)
|
|
|
|
|
|
|
|
.map(diff => `${diff.specification}-${diff.model}-${diff.wire_disc || ''}`)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
return sourceRecords.filter(record => {
|
|
|
|
|
|
|
|
const key = `${record.specification}-${record.model}-${record.wire_disc || ''}`;
|
|
|
|
|
|
|
|
return increaseKeys.has(key);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
case 'decrease':
|
|
|
|
|
|
|
|
// 库存减少:基于差值数据筛选出有负差值的记录
|
|
|
|
|
|
|
|
if (!differenceRecords.value.length) {
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
const decreaseKeys = new Set(
|
|
|
|
|
|
|
|
differenceRecords.value
|
|
|
|
|
|
|
|
.filter(diff => diff.difference < 0)
|
|
|
|
|
|
|
|
.map(diff => `${diff.specification}-${diff.model}-${diff.wire_disc || ''}`)
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
return sourceRecords.filter(record => {
|
|
|
|
|
|
|
|
const key = `${record.specification}-${record.model}-${record.wire_disc || ''}`;
|
|
|
|
|
|
|
|
return decreaseKeys.has(key);
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
case 'all':
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
// 全部:返回所有记录
|
|
|
|
|
|
|
|
return sourceRecords;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:处理机台筛选条件变化
|
|
|
|
|
|
|
|
const handleEquipmentFilterChange = () => {
|
|
|
|
|
|
|
|
console.log('机台筛选条件变化:', equipmentFilter.value);
|
|
|
|
|
|
|
|
// 这里可以直接在表格数据的计算属性中应用筛选逻辑
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:处理筛选条件变化
|
|
|
|
|
|
|
|
const handleFilterChange = () => {
|
|
|
|
|
|
|
|
console.log('筛选条件变化:', inventoryFilter.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果筛选条件不是"全部",确保获取差值数据
|
|
|
|
|
|
|
|
if (inventoryFilter.value !== 'all' && !differenceRecords.value.length) {
|
|
|
|
|
|
|
|
console.log('需要获取差值数据以进行筛选');
|
|
|
|
|
|
|
|
fetchDifferenceData();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:获取转移概率表格数据
|
|
|
|
|
|
|
|
const getTransitionProbabilityTableData = () => {
|
|
|
|
|
|
|
|
if (!currentDialogTransitionData.value || !currentDialogTransitionData.value.current_specification_transitions) {
|
|
|
|
|
|
|
|
return [];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const transitions = currentDialogTransitionData.value.current_specification_transitions;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return Object.entries(transitions).map(([targetSpec, data]) => ({
|
|
|
|
|
|
|
|
targetSpec,
|
|
|
|
|
|
|
|
probability: data.probability,
|
|
|
|
|
|
|
|
count: data.count
|
|
|
|
|
|
|
|
})).sort((a, b) => b.probability - a.probability); // 按概率降序排列
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// WMS对话框相关状态
|
|
|
|
// WMS对话框相关状态
|
|
|
|
const wmsDialogVisible = ref(false)
|
|
|
|
const wmsDialogVisible = ref(false)
|
|
|
|
const currentWmsModel = ref('')
|
|
|
|
const currentWmsModel = ref('')
|
|
|
|
const currentWmsSpecification = ref('')
|
|
|
|
const currentWmsSpecification = ref('')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 当前对话框的转移概率数据
|
|
|
|
|
|
|
|
const currentDialogTransitionData = ref(null)
|
|
|
|
const wmsTableRef = ref(null)
|
|
|
|
const wmsTableRef = ref(null)
|
|
|
|
|
|
|
|
|
|
|
|
// 图表相关状态
|
|
|
|
// 图表相关状态
|
|
|
|
@ -229,21 +419,37 @@ const dynamicColumns = computed(() => {
|
|
|
|
|
|
|
|
|
|
|
|
// 计算属性:表格数据
|
|
|
|
// 计算属性:表格数据
|
|
|
|
const tableData = computed(() => {
|
|
|
|
const tableData = computed(() => {
|
|
|
|
console.log('计算表格数据, records.value:', records.value);
|
|
|
|
console.log('计算表格数据, records.value:', records.value, 'inventoryFilter.value:', inventoryFilter.value, 'equipmentFilter.value:', equipmentFilter.value);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 应用机台筛选
|
|
|
|
|
|
|
|
let filteredRecords = records.value;
|
|
|
|
|
|
|
|
if (equipmentFilter.value !== 'all') {
|
|
|
|
|
|
|
|
filteredRecords = filteredRecords.filter(record => {
|
|
|
|
|
|
|
|
// 检查该记录是否包含被筛选的机台
|
|
|
|
|
|
|
|
const key = `${record.model}::${record.wire_disc || ''}::${record.specification}`;
|
|
|
|
|
|
|
|
return uidProductionStatusMap.value.has(key) &&
|
|
|
|
|
|
|
|
uidProductionStatusMap.value.get(key).equipment_code === equipmentFilter.value;
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log('机台筛选后的记录数量:', filteredRecords.length);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用过滤后的记录
|
|
|
|
|
|
|
|
const finalFilteredRecords = getFilteredRecords(filteredRecords);
|
|
|
|
|
|
|
|
console.log('最终过滤后的记录数量:', finalFilteredRecords.length);
|
|
|
|
|
|
|
|
|
|
|
|
if (!records.value.length) {
|
|
|
|
if (!finalFilteredRecords.length) {
|
|
|
|
console.log('records为空,返回空数组');
|
|
|
|
console.log('过滤后的records为空,返回空数组');
|
|
|
|
return [];
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有唯一的规格并从小到大排序(可选数值排序)
|
|
|
|
// 获取所有唯一的规格并从小到大排序(可选数值排序)
|
|
|
|
const specifications = [...new Set(records.value.map(item => item.specification))]
|
|
|
|
const specifications = [...new Set(finalFilteredRecords.map(item => item.specification))]
|
|
|
|
.sort((a, b) => parseFloat(a) - parseFloat(b)); // 改为数值排序,避免 "0.800" 在前
|
|
|
|
.sort((a, b) => parseFloat(a) - parseFloat(b)); // 改为数值排序,避免 "0.800" 在前
|
|
|
|
|
|
|
|
|
|
|
|
console.log('获取到的规格列表:', specifications);
|
|
|
|
console.log('获取到的规格列表:', specifications);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取所有唯一的 model::wire_disc 组合
|
|
|
|
// 获取所有唯一的 model::wire_disc 组合
|
|
|
|
const combinations = [...new Set(records.value.map(item => {
|
|
|
|
const combinations = [...new Set(finalFilteredRecords.map(item => {
|
|
|
|
if (item.wire_disc && item.wire_disc.trim() !== '') {
|
|
|
|
if (item.wire_disc && item.wire_disc.trim() !== '') {
|
|
|
|
return `${item.model}::${item.wire_disc}`;
|
|
|
|
return `${item.model}::${item.wire_disc}`;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
@ -270,7 +476,7 @@ const tableData = computed(() => {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 查找对应的记录
|
|
|
|
// 查找对应的记录
|
|
|
|
const record = records.value.find(r => {
|
|
|
|
const record = finalFilteredRecords.find(r => {
|
|
|
|
const specMatch = r.specification === specification;
|
|
|
|
const specMatch = r.specification === specification;
|
|
|
|
const modelMatch = r.model === model;
|
|
|
|
const modelMatch = r.model === model;
|
|
|
|
const wireDiscMatch = hasWireDisc
|
|
|
|
const wireDiscMatch = hasWireDisc
|
|
|
|
@ -376,6 +582,9 @@ const fetchUIDProductionStatus = async () => {
|
|
|
|
const uniqueEquipmentCodes = [...new Set(uidProductionStatus.value.map(record => record.equipment_code))];
|
|
|
|
const uniqueEquipmentCodes = [...new Set(uidProductionStatus.value.map(record => record.equipment_code))];
|
|
|
|
console.log('唯一设备代码:', uniqueEquipmentCodes);
|
|
|
|
console.log('唯一设备代码:', uniqueEquipmentCodes);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新机台筛选选项
|
|
|
|
|
|
|
|
equipmentFilterOptions.value = uniqueEquipmentCodes.sort();
|
|
|
|
|
|
|
|
|
|
|
|
// 为每个equipment_code分配颜色
|
|
|
|
// 为每个equipment_code分配颜色
|
|
|
|
uniqueEquipmentCodes.forEach((equipmentCode, index) => {
|
|
|
|
uniqueEquipmentCodes.forEach((equipmentCode, index) => {
|
|
|
|
equipmentColors.set(equipmentCode, generateLowSaturationColor(index));
|
|
|
|
equipmentColors.set(equipmentCode, generateLowSaturationColor(index));
|
|
|
|
@ -467,7 +676,7 @@ const fetchTransitionProbabilities = async (equipmentCode, axleNumber, model, sp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
console.error('获取转移概率数据失败:', result.code, result.message);
|
|
|
|
console.error('获取转移概率数据失败:', result.code, result.message);
|
|
|
|
ElMessage.error(`获取转移概率数据失败: ${result.message || '未知错误'}`);
|
|
|
|
ElMessage.warning(`获取转移概率数据失败: ${result.message || '未知错误'}`);
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
} catch (error) {
|
|
|
|
@ -529,14 +738,106 @@ const generateLowSaturationColor = (index) => {
|
|
|
|
return lowSaturationColors[index % lowSaturationColors.length];
|
|
|
|
return lowSaturationColors[index % lowSaturationColors.length];
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:根据概率值获取颜色
|
|
|
|
// 方法:根据概率值获取背景颜色(用于转移概率显示)
|
|
|
|
const getProbabilityColor = (intensity) => {
|
|
|
|
const getProbabilityBackgroundColor = (intensity, baseColor) => {
|
|
|
|
|
|
|
|
// intensity 是 0-1 之间的值,表示概率的相对强度
|
|
|
|
|
|
|
|
// baseColor 是机台的基础颜色
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有基础颜色,使用默认蓝色
|
|
|
|
|
|
|
|
if (!baseColor) {
|
|
|
|
|
|
|
|
const hue = 220; // 蓝色色调
|
|
|
|
|
|
|
|
const saturation = Math.round(50 + intensity * 50); // 50% 到 100% 饱和度
|
|
|
|
|
|
|
|
const lightness = Math.round(85 - intensity * 50); // 85% 到 35% 亮度
|
|
|
|
|
|
|
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将基础颜色从十六进制转换为HSL
|
|
|
|
|
|
|
|
const rgb = hexToRgb(baseColor);
|
|
|
|
|
|
|
|
if (!rgb) {
|
|
|
|
|
|
|
|
const hue = 220;
|
|
|
|
|
|
|
|
const saturation = Math.round(50 + intensity * 50);
|
|
|
|
|
|
|
|
const lightness = Math.round(85 - intensity * 50);
|
|
|
|
|
|
|
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 为背景色调整饱和度和亮度,确保足够的对比度
|
|
|
|
|
|
|
|
const saturation = Math.min(hsl.s + intensity * 0.6, 1); // 增加饱和度,最大增加60%
|
|
|
|
|
|
|
|
const lightness = Math.max(hsl.l - intensity * 0.4, 0.2); // 降低亮度,最小保持20%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return `hsl(${hsl.h}, ${Math.round(saturation * 100)}%, ${Math.round(lightness * 100)}%)`;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:根据概率值获取文字颜色(保留原有的 getProbabilityColor 方法用于兼容)
|
|
|
|
|
|
|
|
const getProbabilityColor = (intensity, baseColor) => {
|
|
|
|
// intensity 是 0-1 之间的值,表示概率的相对强度
|
|
|
|
// intensity 是 0-1 之间的值,表示概率的相对强度
|
|
|
|
|
|
|
|
// baseColor 是机台的基础颜色
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有基础颜色,回退到默认蓝色
|
|
|
|
|
|
|
|
if (!baseColor) {
|
|
|
|
const hue = 220; // 蓝色色调
|
|
|
|
const hue = 220; // 蓝色色调
|
|
|
|
const saturation = Math.round(30 + intensity * 70); // 30% 到 100% 饱和度
|
|
|
|
const saturation = Math.round(30 + intensity * 70); // 30% 到 100% 饱和度
|
|
|
|
const lightness = Math.round(85 - intensity * 30); // 85% 到 55% 亮度
|
|
|
|
const lightness = Math.round(85 - intensity * 30); // 85% 到 55% 亮度
|
|
|
|
|
|
|
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将基础颜色从十六进制转换为HSL,然后调整饱和度和亮度
|
|
|
|
|
|
|
|
const rgb = hexToRgb(baseColor);
|
|
|
|
|
|
|
|
if (!rgb) {
|
|
|
|
|
|
|
|
// 如果转换失败,使用默认逻辑
|
|
|
|
|
|
|
|
const hue = 220;
|
|
|
|
|
|
|
|
const saturation = Math.round(30 + intensity * 70);
|
|
|
|
|
|
|
|
const lightness = Math.round(85 - intensity * 30);
|
|
|
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
|
|
return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 调整饱和度和亮度来反映概率强度
|
|
|
|
|
|
|
|
const saturation = Math.min(hsl.s + intensity * 0.4, 1); // 增加饱和度,最大增加40%
|
|
|
|
|
|
|
|
const lightness = Math.max(hsl.l - intensity * 0.2, 0.1); // 降低亮度,最小保持10%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return `hsl(${hsl.h}, ${Math.round(saturation * 100)}%, ${Math.round(lightness * 100)}%)`;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:将十六进制颜色转换为RGB
|
|
|
|
|
|
|
|
const hexToRgb = (hex) => {
|
|
|
|
|
|
|
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
|
|
|
|
|
|
|
return result ? {
|
|
|
|
|
|
|
|
r: parseInt(result[1], 16),
|
|
|
|
|
|
|
|
g: parseInt(result[2], 16),
|
|
|
|
|
|
|
|
b: parseInt(result[3], 16)
|
|
|
|
|
|
|
|
} : null;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:将RGB转换为HSL
|
|
|
|
|
|
|
|
const rgbToHsl = (r, g, b) => {
|
|
|
|
|
|
|
|
r /= 255;
|
|
|
|
|
|
|
|
g /= 255;
|
|
|
|
|
|
|
|
b /= 255;
|
|
|
|
|
|
|
|
const max = Math.max(r, g, b);
|
|
|
|
|
|
|
|
const min = Math.min(r, g, b);
|
|
|
|
|
|
|
|
let h, s, l = (max + min) / 2;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (max === min) {
|
|
|
|
|
|
|
|
h = s = 0; // achromatic
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
const d = max - min;
|
|
|
|
|
|
|
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
|
|
|
|
|
|
switch (max) {
|
|
|
|
|
|
|
|
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
|
|
|
|
|
|
case g: h = (b - r) / d + 2; break;
|
|
|
|
|
|
|
|
case b: h = (r - g) / d + 4; break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
h /= 6;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
h: Math.round(h * 360),
|
|
|
|
|
|
|
|
s: s,
|
|
|
|
|
|
|
|
l: l
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:根据wight_completion获取完成度状态
|
|
|
|
// 方法:根据wight_completion获取完成度状态
|
|
|
|
@ -594,7 +895,9 @@ const getEquipmentCodeColor = (specification, columnProp) => {
|
|
|
|
// 构建包含规格的key
|
|
|
|
// 构建包含规格的key
|
|
|
|
const keyWithSpec = `${columnProp}::${specification}`;
|
|
|
|
const keyWithSpec = `${columnProp}::${specification}`;
|
|
|
|
|
|
|
|
|
|
|
|
// 首先检查是否有转移概率数据
|
|
|
|
// 检查该单元格是否处于激活状态
|
|
|
|
|
|
|
|
if (activeCells.value.has(keyWithSpec)) {
|
|
|
|
|
|
|
|
// 如果激活状态,首先检查是否有转移概率数据
|
|
|
|
if (transitionProbabilitiesMap.value.has(keyWithSpec)) {
|
|
|
|
if (transitionProbabilitiesMap.value.has(keyWithSpec)) {
|
|
|
|
const transitionData = transitionProbabilitiesMap.value.get(keyWithSpec);
|
|
|
|
const transitionData = transitionProbabilitiesMap.value.get(keyWithSpec);
|
|
|
|
if (transitionData && transitionData.prediction && transitionData.prediction.most_likely_next_spec) {
|
|
|
|
if (transitionData && transitionData.prediction && transitionData.prediction.most_likely_next_spec) {
|
|
|
|
@ -605,13 +908,14 @@ const getEquipmentCodeColor = (specification, columnProp) => {
|
|
|
|
const colorKey = `${keyWithSpec}::${mostLikelySpec}`;
|
|
|
|
const colorKey = `${keyWithSpec}::${mostLikelySpec}`;
|
|
|
|
if (transitionColorsMap.value.has(colorKey)) {
|
|
|
|
if (transitionColorsMap.value.has(colorKey)) {
|
|
|
|
const baseColor = transitionColorsMap.value.get(colorKey);
|
|
|
|
const baseColor = transitionColorsMap.value.get(colorKey);
|
|
|
|
console.log(`为单元格 ${keyWithSpec} 应用转移概率颜色: ${baseColor}, 概率: ${(probability * 100).toFixed(1)}%`);
|
|
|
|
console.log(`为激活单元格 ${keyWithSpec} 应用转移概率颜色: ${baseColor}, 概率: ${(probability * 100).toFixed(1)}%`);
|
|
|
|
return baseColor;
|
|
|
|
return baseColor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有转移概率数据,回退到设备代码颜色
|
|
|
|
// 如果没有激活或者没有转移概率数据,回退到设备代码颜色
|
|
|
|
if (!uidProductionStatusMap.value.has(keyWithSpec)) {
|
|
|
|
if (!uidProductionStatusMap.value.has(keyWithSpec)) {
|
|
|
|
return null;
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -649,6 +953,92 @@ const getTransitionProbabilityTooltip = (specification, columnProp) => {
|
|
|
|
return tooltip.trim();
|
|
|
|
return tooltip.trim();
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:检查当前单元格是否为目标规格的显示位置
|
|
|
|
|
|
|
|
const isTargetSpecificationCell = (specification, columnProp) => {
|
|
|
|
|
|
|
|
const keyWithSpec = `${columnProp}::${specification}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否有源单元格被激活,且当前规格是目标规格之一
|
|
|
|
|
|
|
|
for (const [sourceKey, sourceData] of transitionProbabilitiesMap.value.entries()) {
|
|
|
|
|
|
|
|
if (!activeCells.value.has(sourceKey)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const transitionData = sourceData;
|
|
|
|
|
|
|
|
if (!transitionData || !transitionData.current_specification_transitions) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查当前规格是否在目标规格列表中
|
|
|
|
|
|
|
|
if (transitionData.current_specification_transitions.hasOwnProperty(specification)) {
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:获取当前单元格的转移概率数据(如果是目标规格)
|
|
|
|
|
|
|
|
const getCellTransitionProbabilityData = (specification, columnProp) => {
|
|
|
|
|
|
|
|
const keyWithSpec = `${columnProp}::${specification}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 遍历所有激活的源单元格
|
|
|
|
|
|
|
|
for (const [sourceKey, sourceData] of transitionProbabilitiesMap.value.entries()) {
|
|
|
|
|
|
|
|
if (!activeCells.value.has(sourceKey)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const transitionData = sourceData;
|
|
|
|
|
|
|
|
if (!transitionData || !transitionData.current_specification_transitions) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查当前规格是否在当前源数据的目标规格列表中
|
|
|
|
|
|
|
|
if (transitionData.current_specification_transitions.hasOwnProperty(specification)) {
|
|
|
|
|
|
|
|
const targetData = transitionData.current_specification_transitions[specification];
|
|
|
|
|
|
|
|
const [sourceModel, sourceWireDisc] = sourceKey.split('::');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 从列属性中提取当前单元格的model和wire_disc
|
|
|
|
|
|
|
|
const hasWireDisc = columnProp.includes('::');
|
|
|
|
|
|
|
|
let currentModel, currentWireDisc;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hasWireDisc) {
|
|
|
|
|
|
|
|
[currentModel, currentWireDisc] = columnProp.split('::');
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
currentModel = columnProp;
|
|
|
|
|
|
|
|
currentWireDisc = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果当前单元格的model和wire_disc与源单元格相同,则显示概率数据
|
|
|
|
|
|
|
|
if (currentModel === sourceModel && currentWireDisc === sourceWireDisc) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
...targetData,
|
|
|
|
|
|
|
|
displayText: `← ${sourceModel}${sourceWireDisc ? '-' + formatWireDisc(sourceWireDisc) : ''}: ${(targetData.probability * 100).toFixed(1)}%`
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:获取概率显示背景颜色
|
|
|
|
|
|
|
|
const getProbabilityColorForDisplay = (probability, specification, columnProp) => {
|
|
|
|
|
|
|
|
// 查找源单元格的基础颜色
|
|
|
|
|
|
|
|
let baseColor = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (const [sourceKey, sourceData] of transitionProbabilitiesMap.value.entries()) {
|
|
|
|
|
|
|
|
if (!activeCells.value.has(sourceKey)) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const transitionData = sourceData;
|
|
|
|
|
|
|
|
if (!transitionData || !transitionData.current_specification_transitions) continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (transitionData.current_specification_transitions.hasOwnProperty(specification)) {
|
|
|
|
|
|
|
|
// 使用源单元格的基础颜色
|
|
|
|
|
|
|
|
if (uidProductionStatusMap.value.has(sourceKey)) {
|
|
|
|
|
|
|
|
const status = uidProductionStatusMap.value.get(sourceKey);
|
|
|
|
|
|
|
|
baseColor = status.equipment_color;
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用新的背景色方法
|
|
|
|
|
|
|
|
const intensity = probability; // probability 已经是 0-1 之间的值
|
|
|
|
|
|
|
|
return getProbabilityBackgroundColor(intensity, baseColor);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:获取单元格悬停提示
|
|
|
|
// 方法:获取单元格悬停提示
|
|
|
|
const getCellTooltip = (specification, columnProp) => {
|
|
|
|
const getCellTooltip = (specification, columnProp) => {
|
|
|
|
// 构建包含规格的key
|
|
|
|
// 构建包含规格的key
|
|
|
|
@ -696,7 +1086,16 @@ const getDifferenceClass = (difference) => {
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:处理单元格单击事件 - 获取转移概率数据
|
|
|
|
// 方法:处理单元格单击事件 - 获取转移概率数据
|
|
|
|
|
|
|
|
// 处理单元格单击事件 - 获取转移概率数据(带防抖)
|
|
|
|
const handleCellClick = async (row, column, cell, event) => {
|
|
|
|
const handleCellClick = async (row, column, cell, event) => {
|
|
|
|
|
|
|
|
// 清除之前的延时器
|
|
|
|
|
|
|
|
if (clickTimeoutId) {
|
|
|
|
|
|
|
|
clearTimeout(clickTimeoutId);
|
|
|
|
|
|
|
|
clickTimeoutId = null;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置延时器,延迟执行单击逻辑
|
|
|
|
|
|
|
|
clickTimeoutId = setTimeout(async () => {
|
|
|
|
const cellValue = row[column.property];
|
|
|
|
const cellValue = row[column.property];
|
|
|
|
|
|
|
|
|
|
|
|
// 检查单元格是否有值
|
|
|
|
// 检查单元格是否有值
|
|
|
|
@ -721,15 +1120,33 @@ const handleCellClick = async (row, column, cell, event) => {
|
|
|
|
wire_disc = null;
|
|
|
|
wire_disc = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 构建单元格键值
|
|
|
|
|
|
|
|
const keyWithSpec = `${columnKey}::${row.specification}`;
|
|
|
|
|
|
|
|
|
|
|
|
console.log('单击事件参数:', {
|
|
|
|
console.log('单击事件参数:', {
|
|
|
|
columnKey,
|
|
|
|
columnKey,
|
|
|
|
model,
|
|
|
|
model,
|
|
|
|
wire_disc,
|
|
|
|
wire_disc,
|
|
|
|
specification: row.specification
|
|
|
|
specification: row.specification,
|
|
|
|
|
|
|
|
keyWithSpec
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查该单元格是否已经激活
|
|
|
|
|
|
|
|
if (activeCells.value.has(keyWithSpec)) {
|
|
|
|
|
|
|
|
// 如果已经激活,则取消激活状态
|
|
|
|
|
|
|
|
activeCells.value.delete(keyWithSpec);
|
|
|
|
|
|
|
|
console.log(`单元格 ${keyWithSpec} 已取消激活,恢复原始颜色`);
|
|
|
|
|
|
|
|
ElMessage.info('已取消概率颜色显示');
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果激活了其他单元格,先取消所有之前的激活状态(单选模式)
|
|
|
|
|
|
|
|
if (activeCells.value.size > 0) {
|
|
|
|
|
|
|
|
console.log('取消所有之前激活的单元格:', Array.from(activeCells.value));
|
|
|
|
|
|
|
|
activeCells.value.clear();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取对应的机台信息和轴数
|
|
|
|
// 获取对应的机台信息和轴数
|
|
|
|
const keyWithSpec = `${columnKey}::${row.specification}`;
|
|
|
|
|
|
|
|
let equipmentCode = 'QB002'; // 默认值
|
|
|
|
let equipmentCode = 'QB002'; // 默认值
|
|
|
|
let axleNumber = '左边'; // 默认值
|
|
|
|
let axleNumber = '左边'; // 默认值
|
|
|
|
|
|
|
|
|
|
|
|
@ -749,7 +1166,9 @@ const handleCellClick = async (row, column, cell, event) => {
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经获取过该单元格的转移概率数据
|
|
|
|
// 检查是否已经获取过该单元格的转移概率数据
|
|
|
|
if (transitionProbabilitiesMap.value.has(keyWithSpec)) {
|
|
|
|
if (transitionProbabilitiesMap.value.has(keyWithSpec)) {
|
|
|
|
console.log('该单元格的转移概率数据已存在,跳过API调用');
|
|
|
|
console.log('该单元格的转移概率数据已存在,直接激活显示');
|
|
|
|
|
|
|
|
activeCells.value.add(keyWithSpec);
|
|
|
|
|
|
|
|
ElMessage.success('转移概率数据已显示');
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -774,27 +1193,59 @@ const handleCellClick = async (row, column, cell, event) => {
|
|
|
|
Object.entries(probabilities).forEach(([targetSpec, data]) => {
|
|
|
|
Object.entries(probabilities).forEach(([targetSpec, data]) => {
|
|
|
|
const colorKey = `${transitionsKey}::${targetSpec}`;
|
|
|
|
const colorKey = `${transitionsKey}::${targetSpec}`;
|
|
|
|
const intensity = data.probability / maxProbability; // 0-1之间的强度值
|
|
|
|
const intensity = data.probability / maxProbability; // 0-1之间的强度值
|
|
|
|
const color = getProbabilityColor(intensity);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取机台的基础颜色
|
|
|
|
|
|
|
|
const keyWithSpec = `${columnKey}::${row.specification}`;
|
|
|
|
|
|
|
|
let baseColor = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (uidProductionStatusMap.value.has(keyWithSpec)) {
|
|
|
|
|
|
|
|
const status = uidProductionStatusMap.value.get(keyWithSpec);
|
|
|
|
|
|
|
|
baseColor = status.equipment_color;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const color = getProbabilityColor(intensity, baseColor);
|
|
|
|
transitionColorsMap.value.set(colorKey, color);
|
|
|
|
transitionColorsMap.value.set(colorKey, color);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
console.log('转移概率数据已存储:', transitionProbabilitiesMap.value);
|
|
|
|
console.log('转移概率数据已存储:', transitionProbabilitiesMap.value);
|
|
|
|
console.log('概率颜色映射:', transitionColorsMap.value);
|
|
|
|
console.log('概率颜色映射:', transitionColorsMap.value);
|
|
|
|
|
|
|
|
|
|
|
|
ElMessage.success('转移概率数据已加载');
|
|
|
|
// 激活该单元格
|
|
|
|
|
|
|
|
activeCells.value.add(keyWithSpec);
|
|
|
|
|
|
|
|
ElMessage.success('转移概率数据已加载并显示');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}, DBL_CLICK_DELAY);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 方法:处理单元格双击事件 - 显示WMS详情
|
|
|
|
// 方法:处理单元格双击事件 - 显示WMS详情和转移概率
|
|
|
|
const handleCellDblClick = (row, column, cell, event) => {
|
|
|
|
const handleCellDblClick = async (row, column, cell, event) => {
|
|
|
|
|
|
|
|
// 清除单击事件的延时器,防止双击时触发单击逻辑
|
|
|
|
|
|
|
|
if (clickTimeoutId) {
|
|
|
|
|
|
|
|
clearTimeout(clickTimeoutId);
|
|
|
|
|
|
|
|
clickTimeoutId = null;
|
|
|
|
|
|
|
|
console.log('双击事件已清除单击延时器');
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 调试信息
|
|
|
|
|
|
|
|
console.log('双击事件触发:', {
|
|
|
|
|
|
|
|
row,
|
|
|
|
|
|
|
|
column,
|
|
|
|
|
|
|
|
columnProperty: column.property,
|
|
|
|
|
|
|
|
cellValue: row[column.property],
|
|
|
|
|
|
|
|
cellValueType: typeof row[column.property]
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const cellValue = row[column.property];
|
|
|
|
const cellValue = row[column.property];
|
|
|
|
|
|
|
|
|
|
|
|
// 检查单元格是否有值
|
|
|
|
// 放宽单元格值检查条件,只在明确为空的情况下才返回
|
|
|
|
if (!cellValue || cellValue === '-' || cellValue === null || cellValue === undefined) {
|
|
|
|
if (cellValue === null || cellValue === undefined) {
|
|
|
|
ElMessage.warning('该单元格暂无数据');
|
|
|
|
ElMessage.warning('该单元格暂无数据');
|
|
|
|
return;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 移除对空字符串和'-'的检查,让这些值也能打开对话框
|
|
|
|
|
|
|
|
console.log('单元格值检查通过,继续执行');
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否是规格列或总计列,这些列不需要显示WMS详情
|
|
|
|
// 检查是否是规格列或总计列,这些列不需要显示WMS详情
|
|
|
|
if (column.property === 'specification' || column.property === 'total') {
|
|
|
|
if (column.property === 'specification' || column.property === 'total') {
|
|
|
|
ElMessage.info('该列不支持查看详情');
|
|
|
|
ElMessage.info('该列不支持查看详情');
|
|
|
|
@ -833,6 +1284,56 @@ const handleCellDblClick = (row, column, cell, event) => {
|
|
|
|
|
|
|
|
|
|
|
|
// 获取库存历史数据
|
|
|
|
// 获取库存历史数据
|
|
|
|
fetchInventoryHistoryData(model, row.specification, wire_disc);
|
|
|
|
fetchInventoryHistoryData(model, row.specification, wire_disc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取转移概率数据(用于表格显示)
|
|
|
|
|
|
|
|
const keyWithSpec = `${columnKey}::${row.specification}`;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取对应的机台信息和轴数
|
|
|
|
|
|
|
|
let equipmentCode = 'QB002'; // 默认值
|
|
|
|
|
|
|
|
let axleNumber = '左边'; // 默认值
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (uidProductionStatusMap.value.has(keyWithSpec)) {
|
|
|
|
|
|
|
|
const status = uidProductionStatusMap.value.get(keyWithSpec);
|
|
|
|
|
|
|
|
equipmentCode = status.equipment_code || 'QB002';
|
|
|
|
|
|
|
|
axleNumber = status.axle_number || '左边';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('双击事件获取转移概率参数:', {
|
|
|
|
|
|
|
|
equipmentCode,
|
|
|
|
|
|
|
|
axleNumber,
|
|
|
|
|
|
|
|
model,
|
|
|
|
|
|
|
|
specification: row.specification,
|
|
|
|
|
|
|
|
wireDisc: formatWireDisc(wire_disc || '')
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否已经获取过该单元格的转移概率数据
|
|
|
|
|
|
|
|
if (transitionProbabilitiesMap.value.has(keyWithSpec)) {
|
|
|
|
|
|
|
|
console.log('双击事件:该单元格的转移概率数据已存在');
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取转移概率数据
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
|
|
const transitionData = await fetchTransitionProbabilities(
|
|
|
|
|
|
|
|
equipmentCode,
|
|
|
|
|
|
|
|
axleNumber,
|
|
|
|
|
|
|
|
model,
|
|
|
|
|
|
|
|
row.specification,
|
|
|
|
|
|
|
|
formatWireDisc(wire_disc || '')
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (transitionData && transitionData.current_specification_transitions) {
|
|
|
|
|
|
|
|
// 存储转移概率数据
|
|
|
|
|
|
|
|
const transitionsKey = `${columnKey}::${row.specification}`;
|
|
|
|
|
|
|
|
transitionProbabilitiesMap.value.set(transitionsKey, transitionData);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 设置当前对话框的转移概率数据
|
|
|
|
|
|
|
|
currentDialogTransitionData.value = transitionData;
|
|
|
|
|
|
|
|
console.log('双击事件:转移概率数据已存储到对话框表格:', transitionData);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
|
|
console.error('双击事件:获取转移概率数据失败:', error);
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取销量数据
|
|
|
|
// 获取销量数据
|
|
|
|
@ -1388,6 +1889,9 @@ const handleDialogClose = () => {
|
|
|
|
historyData.value = [];
|
|
|
|
historyData.value = [];
|
|
|
|
hasHistoryData.value = false;
|
|
|
|
hasHistoryData.value = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 清空当前对话框的转移概率数据
|
|
|
|
|
|
|
|
currentDialogTransitionData.value = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 移除窗口大小变化监听器
|
|
|
|
// 移除窗口大小变化监听器
|
|
|
|
window.removeEventListener('resize', resizeInventoryChart);
|
|
|
|
window.removeEventListener('resize', resizeInventoryChart);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
@ -1451,6 +1955,10 @@ onMounted(() => {
|
|
|
|
white-space: nowrap;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-align: center; /* 可选:居中对齐列头 */
|
|
|
|
text-align: center; /* 可选:居中对齐列头 */
|
|
|
|
padding: 8px 0; /* 调整列头内间距,以适应两行显示 */
|
|
|
|
padding: 8px 0; /* 调整列头内间距,以适应两行显示 */
|
|
|
|
|
|
|
|
position: sticky;
|
|
|
|
|
|
|
|
top: 0;
|
|
|
|
|
|
|
|
z-index: 10;
|
|
|
|
|
|
|
|
border-bottom: 2px solid #dcdfe6;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
:deep(.el-table td) {
|
|
|
|
:deep(.el-table td) {
|
|
|
|
|