|
@@ -89,8 +89,9 @@
|
|
<ContentWrap>
|
|
<ContentWrap>
|
|
<!-- 列表 -->
|
|
<!-- 列表 -->
|
|
<ContentWrap>
|
|
<ContentWrap>
|
|
- <el-table v-loading="loading" :data="paginatedList" :stripe="true" :show-overflow-tooltip="true" :header-cell-style="tableHeaderStyle">
|
|
|
|
- <!-- 添加序号列 -->
|
|
|
|
|
|
+ <el-table v-loading="loading" :data="paginatedList" :stripe="true"
|
|
|
|
+ :show-overflow-tooltip="true" :header-cell-style="tableHeaderStyle" :span-method="handleSpanMethod">
|
|
|
|
+ <!-- 序号列 -->
|
|
<el-table-column
|
|
<el-table-column
|
|
type="index"
|
|
type="index"
|
|
:label="t('maintain.serial')"
|
|
:label="t('maintain.serial')"
|
|
@@ -122,6 +123,7 @@
|
|
prop="group"
|
|
prop="group"
|
|
fixed="left"
|
|
fixed="left"
|
|
:width="columnWidths.group"
|
|
:width="columnWidths.group"
|
|
|
|
+ :cell-class-name="groupCellClassName"
|
|
>
|
|
>
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
<div class="full-content-cell">
|
|
<div class="full-content-cell">
|
|
@@ -132,8 +134,9 @@
|
|
<el-table-column :label="t('mainPlan.MaintItems')" align="center" prop="name"
|
|
<el-table-column :label="t('mainPlan.MaintItems')" align="center" prop="name"
|
|
:show-overflow-tooltip="false" :width="columnWidths.name" fixed="left">
|
|
:show-overflow-tooltip="false" :width="columnWidths.name" fixed="left">
|
|
<template #default="{ row }">
|
|
<template #default="{ row }">
|
|
- <div class="full-content-cell"> <!-- 自定义样式 -->
|
|
|
|
- {{ row.name }}
|
|
|
|
|
|
+ <div class="full-content-cell">
|
|
|
|
+ <!-- 保养项 只显示'->'后的内容 -->
|
|
|
|
+ {{ formatMaintItemName(row.name) }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
@@ -693,7 +696,6 @@ const materialList = ref<IotMainWorkOrderBomMaterialVO[]>([]) // 保养工单bom
|
|
const deviceIds = ref<number[]>([]) // 已经选择的设备id数组
|
|
const deviceIds = ref<number[]>([]) // 已经选择的设备id数组
|
|
const { params, name } = useRoute() // 查询参数
|
|
const { params, name } = useRoute() // 查询参数
|
|
const id = params.id
|
|
const id = params.id
|
|
-const devicePersonsMap = ref<Map<number, Set<string>>>(new Map()) // 存储设备-责任人映射
|
|
|
|
// 控制抽屉额外列的显示
|
|
// 控制抽屉额外列的显示
|
|
const hideExtraColumnsInDrawer = ref(false)
|
|
const hideExtraColumnsInDrawer = ref(false)
|
|
|
|
|
|
@@ -709,8 +711,14 @@ const maintItemsWidth = ref('auto')
|
|
const lastNaturalDateWatchers = ref(new Map())
|
|
const lastNaturalDateWatchers = ref(new Map())
|
|
|
|
|
|
const columnWidths = ref<Record<string, string>>({});
|
|
const columnWidths = ref<Record<string, string>>({});
|
|
-// 响应式变量
|
|
|
|
-const currentPageSpanArr = ref<number[]>([])
|
|
|
|
|
|
+
|
|
|
|
+// 计算当前页是否有分组数据
|
|
|
|
+const hasGroupInCurrentPage = computed(() => {
|
|
|
|
+ return paginatedList.value.some(item => item.group && item.group !== '');
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+// 分组合并计算逻辑
|
|
|
|
+const groupSpans = ref<Record<string, { span: number, index: number }>>({})
|
|
|
|
|
|
const formData = ref({
|
|
const formData = ref({
|
|
id: undefined,
|
|
id: undefined,
|
|
@@ -868,6 +876,104 @@ const openConfigDialog = (row: IotMainWorkOrderBomVO) => {
|
|
configDialog.visible = true
|
|
configDialog.visible = true
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// 格式化 保养项名称 方法 只显示 -> 后面的内容
|
|
|
|
+const formatMaintItemName = (name: string) => {
|
|
|
|
+ if (!name) return '';
|
|
|
|
+
|
|
|
|
+ // 包含'->'时只取后半部分
|
|
|
|
+ if (name.includes('->')) {
|
|
|
|
+ return name.split('->').pop()?.trim() || name;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 不含'->'时显示完整内容
|
|
|
|
+ return name;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 行合并方法 (优化后符合图片效果)
|
|
|
|
+const handleSpanMethod = ({ row, column, rowIndex, columnIndex }) => {
|
|
|
|
+ // 只处理保养项组列
|
|
|
|
+ if (column.property === 'group' && row.group) {
|
|
|
|
+ const groupKey = `${currentPage.value}-${row.group}`;
|
|
|
|
+ const spanInfo = groupSpans.value[groupKey];
|
|
|
|
+
|
|
|
|
+ if (spanInfo && rowIndex === spanInfo.index) {
|
|
|
|
+ return {
|
|
|
|
+ rowspan: spanInfo.span,
|
|
|
|
+ colspan: 1
|
|
|
|
+ };
|
|
|
|
+ } else {
|
|
|
|
+ return {
|
|
|
|
+ rowspan: 0,
|
|
|
|
+ colspan: 0
|
|
|
|
+ };
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 其他列不合并
|
|
|
|
+ return {
|
|
|
|
+ rowspan: 1,
|
|
|
|
+ colspan: 1
|
|
|
|
+ };
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 计算分组合并信息 (优化后符合图片效果)
|
|
|
|
+const calculateGroupSpans = () => {
|
|
|
|
+ // 重置分组信息
|
|
|
|
+ groupSpans.value = {};
|
|
|
|
+
|
|
|
|
+ const pageKey = currentPage.value;
|
|
|
|
+ let currentGroup = '';
|
|
|
|
+ let groupStartIndex = 0;
|
|
|
|
+ let groupCount = 0;
|
|
|
|
+
|
|
|
|
+ // 先清除所有行的分组标记
|
|
|
|
+ paginatedList.value.forEach(item => {
|
|
|
|
+ delete item.isGroupFirstRow;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ paginatedList.value.forEach((item, index) => {
|
|
|
|
+ // 获取当前行的分组(从name中提取)
|
|
|
|
+ const group = item.name && item.name.includes('->')
|
|
|
|
+ ? item.name.split('->')[0].trim()
|
|
|
|
+ : '';
|
|
|
|
+
|
|
|
|
+ // 如果分组变化
|
|
|
|
+ if (group !== currentGroup) {
|
|
|
|
+ // 保存上一个分组的信息
|
|
|
|
+ if (currentGroup && groupCount > 0) {
|
|
|
|
+ const groupKey = `${pageKey}-${currentGroup}`;
|
|
|
|
+ groupSpans.value[groupKey] = {
|
|
|
|
+ span: groupCount,
|
|
|
|
+ index: groupStartIndex
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 标记上一个分组的起始行(添加这行)
|
|
|
|
+ paginatedList.value[groupStartIndex].isGroupFirstRow = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 开始新分组
|
|
|
|
+ currentGroup = group;
|
|
|
|
+ groupStartIndex = index;
|
|
|
|
+ groupCount = 1;
|
|
|
|
+ } else {
|
|
|
|
+ // 相同分组,计数增加
|
|
|
|
+ groupCount++;
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 保存最后一个分组的信息
|
|
|
|
+ if (currentGroup && groupCount > 0) {
|
|
|
|
+ const groupKey = `${pageKey}-${currentGroup}`;
|
|
|
|
+ groupSpans.value[groupKey] = {
|
|
|
|
+ span: groupCount,
|
|
|
|
+ index: groupStartIndex
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 标记最后一个分组的起始行(添加这行)
|
|
|
|
+ paginatedList.value[groupStartIndex].isGroupFirstRow = true;
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
// 运行时间周期 单行校验方法
|
|
// 运行时间周期 单行校验方法
|
|
const validateRunningTime = (row: IotMainWorkOrderBomVO) => {
|
|
const validateRunningTime = (row: IotMainWorkOrderBomVO) => {
|
|
if (row.runningTimeRule === 0 && (!row.nextRunningTime || row.nextRunningTime <= 0)) {
|
|
if (row.runningTimeRule === 0 && (!row.nextRunningTime || row.nextRunningTime <= 0)) {
|
|
@@ -1095,6 +1201,14 @@ const close = () => {
|
|
push({ name: 'IotMainWorkOrder', params:{}})
|
|
push({ name: 'IotMainWorkOrder', params:{}})
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// 分组单元格类名方法
|
|
|
|
+const groupCellClassName = ({ row, column }) => {
|
|
|
|
+ if (column.property === 'group' && row.isGroupFirstRow) {
|
|
|
|
+ return 'group-first-row';
|
|
|
|
+ }
|
|
|
|
+ return '';
|
|
|
|
+};
|
|
|
|
+
|
|
/** 提交表单 */
|
|
/** 提交表单 */
|
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
|
|
const submitForm = async () => {
|
|
const submitForm = async () => {
|
|
@@ -1187,12 +1301,15 @@ const configFormRules = reactive({
|
|
|
|
|
|
// 计算文本宽度的辅助函数
|
|
// 计算文本宽度的辅助函数
|
|
const getTextWidth = (text: string, fontSize = 14): number => {
|
|
const getTextWidth = (text: string, fontSize = 14): number => {
|
|
|
|
+ if (!text) return 0;
|
|
|
|
+
|
|
const span = document.createElement('span')
|
|
const span = document.createElement('span')
|
|
span.style.visibility = 'hidden'
|
|
span.style.visibility = 'hidden'
|
|
span.style.position = 'absolute'
|
|
span.style.position = 'absolute'
|
|
span.style.whiteSpace = 'nowrap'
|
|
span.style.whiteSpace = 'nowrap'
|
|
- span.style.fontSize = '14px' // 与表格实际字体一致
|
|
|
|
|
|
+ span.style.fontSize = `${fontSize}px` // 与表格实际字体一致
|
|
span.style.fontFamily = 'inherit'
|
|
span.style.fontFamily = 'inherit'
|
|
|
|
+ span.style.fontWeight = 'normal';
|
|
span.innerText = text
|
|
span.innerText = text
|
|
document.body.appendChild(span)
|
|
document.body.appendChild(span)
|
|
const width = span.offsetWidth
|
|
const width = span.offsetWidth
|
|
@@ -1358,7 +1475,7 @@ const calculateAllColumnsWidth = () => {
|
|
const MIN_WIDTH = 70; // 最小列宽
|
|
const MIN_WIDTH = 70; // 最小列宽
|
|
const PADDING = 10; // 列内边距
|
|
const PADDING = 10; // 列内边距
|
|
const FIXED_COLUMN_PADDING = 10; // 固定列额外内边距
|
|
const FIXED_COLUMN_PADDING = 10; // 固定列额外内边距
|
|
- const GROUP_COLUMN_EXTRA = 20; // 分组列额外宽度
|
|
|
|
|
|
+ const GROUP_COLUMN_EXTRA = 10; // 分组列额外宽度
|
|
|
|
|
|
// 需要自适应的列配置
|
|
// 需要自适应的列配置
|
|
const autoColumns = [
|
|
const autoColumns = [
|
|
@@ -1418,8 +1535,9 @@ const calculateAllColumnsWidth = () => {
|
|
}
|
|
}
|
|
// 取最大值并添加内边距
|
|
// 取最大值并添加内边距
|
|
let finalWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
|
|
let finalWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
|
|
- // 为分组列增加额外宽度(重点修改)
|
|
|
|
|
|
+ // 为分组列增加额外宽度
|
|
if ([
|
|
if ([
|
|
|
|
+ 'group',
|
|
'lastRunningKilometers',
|
|
'lastRunningKilometers',
|
|
'nextMaintenanceKm',
|
|
'nextMaintenanceKm',
|
|
'remainKm',
|
|
'remainKm',
|
|
@@ -1485,6 +1603,13 @@ watch([paginatedList, hasMileageRuleInCurrentPage, hasTimeRuleInCurrentPage, has
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
|
|
|
|
+// 监听分页变化时重新计算分组信息
|
|
|
|
+watch([paginatedList, currentPage], () => {
|
|
|
|
+ calculateGroupSpans();
|
|
|
|
+ calculateAllColumnsWidth();
|
|
|
|
+ tableRef.value?.doLayout(); // 确保表格重新布局
|
|
|
|
+});
|
|
|
|
+
|
|
// 下拉菜单命令处理
|
|
// 下拉菜单命令处理
|
|
const handleDropdownCommand = (command: { action: string; row: IotMainWorkOrderBomVO }) => {
|
|
const handleDropdownCommand = (command: { action: string; row: IotMainWorkOrderBomVO }) => {
|
|
switch (command.action) {
|
|
switch (command.action) {
|
|
@@ -1631,24 +1756,24 @@ onMounted(async () => {
|
|
list.value = []
|
|
list.value = []
|
|
if (Array.isArray(data)) {
|
|
if (Array.isArray(data)) {
|
|
list.value = data.map(item => {
|
|
list.value = data.map(item => {
|
|
- // 提取分组名称
|
|
|
|
- const group = item.name && item.name.includes('->')
|
|
|
|
- ? item.name.split('->')[0].trim()
|
|
|
|
- : '';
|
|
|
|
-
|
|
|
|
- if (item.mileageRule === 0) {
|
|
|
|
- item.nextMaintenanceKm = calculateNextMaintenanceKm(item);
|
|
|
|
- item.remainKm = calculateRemainKm(item);
|
|
|
|
- }
|
|
|
|
- if (item.runningTimeRule === 0) {
|
|
|
|
- item.nextMaintenanceH = calculateNextMaintenanceH(item);
|
|
|
|
- item.remainH = calculateRemainH(item);
|
|
|
|
- }
|
|
|
|
- if (item.naturalDateRule === 0) {
|
|
|
|
- item.nextMaintenanceDate = calculateNextMaintenanceDate(item);
|
|
|
|
- item.remainDay = calculateRemainDay(item);
|
|
|
|
- }
|
|
|
|
- setupNaturalDateSync(item);
|
|
|
|
|
|
+ // 提取分组名称
|
|
|
|
+ const group = item.name && item.name.includes('->')
|
|
|
|
+ ? item.name.split('->')[0].trim()
|
|
|
|
+ : '';
|
|
|
|
+
|
|
|
|
+ if (item.mileageRule === 0) {
|
|
|
|
+ item.nextMaintenanceKm = calculateNextMaintenanceKm(item);
|
|
|
|
+ item.remainKm = calculateRemainKm(item);
|
|
|
|
+ }
|
|
|
|
+ if (item.runningTimeRule === 0) {
|
|
|
|
+ item.nextMaintenanceH = calculateNextMaintenanceH(item);
|
|
|
|
+ item.remainH = calculateRemainH(item);
|
|
|
|
+ }
|
|
|
|
+ if (item.naturalDateRule === 0) {
|
|
|
|
+ item.nextMaintenanceDate = calculateNextMaintenanceDate(item);
|
|
|
|
+ item.remainDay = calculateRemainDay(item);
|
|
|
|
+ }
|
|
|
|
+ setupNaturalDateSync(item);
|
|
return {
|
|
return {
|
|
...item,
|
|
...item,
|
|
group,
|
|
group,
|
|
@@ -1679,6 +1804,9 @@ onMounted(async () => {
|
|
calculateAllColumnsWidth()
|
|
calculateAllColumnsWidth()
|
|
window.addEventListener('resize', calculateAllColumnsWidth);
|
|
window.addEventListener('resize', calculateAllColumnsWidth);
|
|
})
|
|
})
|
|
|
|
+
|
|
|
|
+ // 初始化 保养项 分组信息
|
|
|
|
+ calculateGroupSpans();
|
|
})
|
|
})
|
|
|
|
|
|
onUnmounted(async () => {
|
|
onUnmounted(async () => {
|
|
@@ -1739,7 +1867,7 @@ onUnmounted(async () => {
|
|
overflow: visible; /* 允许内容溢出单元格 */
|
|
overflow: visible; /* 允许内容溢出单元格 */
|
|
}
|
|
}
|
|
|
|
|
|
-/* 新增分组表头样式 */
|
|
|
|
|
|
+/* 分组表头样式 */
|
|
:deep(.el-table__header) {
|
|
:deep(.el-table__header) {
|
|
border: 1px solid #dcdfe6 !important;
|
|
border: 1px solid #dcdfe6 !important;
|
|
}
|
|
}
|
|
@@ -1761,4 +1889,37 @@ onUnmounted(async () => {
|
|
:deep(.el-table__header .el-table__cell:not(.is-group)) {
|
|
:deep(.el-table__header .el-table__cell:not(.is-group)) {
|
|
border-top: 1px solid #dcdfe6 !important; /* 添加顶部边框连接分组标题 */
|
|
border-top: 1px solid #dcdfe6 !important; /* 添加顶部边框连接分组标题 */
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+/* 分组行样式 - 符合图片效果 */
|
|
|
|
+:deep(.el-table .group-row) {
|
|
|
|
+ background-color: #f8f8f9; /* 轻微的背景色区分 */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 分组单元格样式 */
|
|
|
|
+:deep(.el-table .group-cell) {
|
|
|
|
+ font-weight: 600; /* 加粗字体 */
|
|
|
|
+ vertical-align: middle; /* 垂直居中 */
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 分组第一行单元格样式 - 添加底部边框 */
|
|
|
|
+:deep(.el-table .group-first-row) {
|
|
|
|
+ position: relative;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 使用伪元素创建更明显的底部边框 */
|
|
|
|
+:deep(.el-table .group-first-row::after) {
|
|
|
|
+ content: '';
|
|
|
|
+ position: absolute;
|
|
|
|
+ left: 0;
|
|
|
|
+ right: 0;
|
|
|
|
+ bottom: 0;
|
|
|
|
+ height: 2px;
|
|
|
|
+ background-color: #606266; /* 深灰色边框 */
|
|
|
|
+ z-index: 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 调整分组行的高度,使边框更明显 */
|
|
|
|
+:deep(.el-table .el-table__row.group-first-row) {
|
|
|
|
+ border-bottom: none; /* 移除默认边框 */
|
|
|
|
+}
|
|
</style>
|
|
</style>
|