|
@@ -45,11 +45,13 @@
|
|
|
:data="list"
|
|
|
:stripe="true"
|
|
|
ref="tableRef"
|
|
|
- :show-overflow-tooltip="true"
|
|
|
+ :show-overflow-tooltip="false"
|
|
|
@row-click="handleRowClick"
|
|
|
:max-height="effectiveTableHeight"
|
|
|
+ style="width: 100%; min-width: 100%"
|
|
|
+ class="fixed-layout-table"
|
|
|
>
|
|
|
- <el-table-column width="70" :label="t('workOrderMaterial.select')">
|
|
|
+ <el-table-column width="60" :label="t('workOrderMaterial.select')">
|
|
|
<template #default="{ row }">
|
|
|
<el-checkbox
|
|
|
:model-value="selectedRows.some(item => item.id === row.id)"
|
|
@@ -58,11 +60,17 @@
|
|
|
/>
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column :label="t('chooseMaintain.deviceCode')" align="center" prop="deviceCode" />
|
|
|
- <el-table-column :label="t('deviceList.deviceName')" align="center" prop="deviceName" />
|
|
|
+ <el-table-column :label="t('chooseMaintain.deviceCode')" align="center" prop="deviceCode" :min-width="flexColumnMinWidths.deviceCode"/>
|
|
|
+ <el-table-column :label="t('deviceList.deviceName')" align="center" prop="deviceName" :min-width="flexColumnMinWidths.deviceName">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="flex-cell">
|
|
|
+ {{ row.deviceName }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
<el-table-column :label="t('faultForm.deptId')" align="center" prop="deptId" v-if="false"/>
|
|
|
- <el-table-column :label="t('iotDevice.dept')" align="center" prop="deptName" />
|
|
|
- <el-table-column :label="t('iotDevice.status')" align="center" prop="deviceStatus">
|
|
|
+ <el-table-column :label="t('iotDevice.dept')" align="center" prop="deptName" :min-width="flexColumnMinWidths.deptName"/>
|
|
|
+ <el-table-column :label="t('iotDevice.status')" align="center" prop="deviceStatus" :min-width="flexColumnMinWidths.deviceStatus">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :type="DICT_TYPE.PMS_DEVICE_STATUS" :value="scope.row.deviceStatus" />
|
|
|
</template>
|
|
@@ -71,9 +79,14 @@
|
|
|
:label="t('deviceList.createTime')"
|
|
|
align="center"
|
|
|
prop="createTime"
|
|
|
- width="180"
|
|
|
- :formatter="dateFormatter"
|
|
|
- />
|
|
|
+ :min-width="flexColumnMinWidths.createTime"
|
|
|
+ >
|
|
|
+ <template #default="{ row }">
|
|
|
+ <div class="date-cell">
|
|
|
+ {{ formatDateTime(row.createTime) }}
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
</el-table>
|
|
|
</div>
|
|
|
|
|
@@ -122,13 +135,22 @@ const queryParams = reactive({
|
|
|
code: undefined
|
|
|
})
|
|
|
|
|
|
-// 新增响应式变量
|
|
|
+// 响应式变量
|
|
|
const dialogWidth = ref('1100px');
|
|
|
const tableMinHeight = ref(400); // 初始最小高度
|
|
|
const effectiveTableHeight = ref<number | null>(null); // 单一高度变量
|
|
|
-const tableDynamicHeight = ref('auto'); // 新增动态高度变量
|
|
|
const dialogTopRef = ref<HTMLElement | null>(null);
|
|
|
const showPagination = ref(false); // 控制分页显示
|
|
|
+const tableContainerWidth = ref(0) // 表格容器宽度
|
|
|
+
|
|
|
+// 弹性列最小宽度记录
|
|
|
+const flexColumnMinWidths = reactive({
|
|
|
+ deviceCode: 0,
|
|
|
+ deviceName: 0,
|
|
|
+ deptName: 0,
|
|
|
+ deviceStatus: 0,
|
|
|
+ createTime: 0
|
|
|
+})
|
|
|
|
|
|
// 点击整行选中
|
|
|
const handleRowClick = (row) => {
|
|
@@ -163,6 +185,145 @@ const open = async () => {
|
|
|
defineExpose({ open })
|
|
|
const { wsCache } = useCache()
|
|
|
|
|
|
+// 文本测量工具函数
|
|
|
+const measureText = (text: string, fontSize: string = '14px',
|
|
|
+ fontWeight: string = 'normal', extraStyles: Record<string, string> = {}): number => {
|
|
|
+ const span = document.createElement('span')
|
|
|
+ span.style.visibility = 'hidden'
|
|
|
+ span.style.position = 'absolute'
|
|
|
+ span.style.fontSize = fontSize
|
|
|
+ span.style.fontWeight = fontWeight
|
|
|
+ span.style.fontFamily = "'Microsoft YaHei', sans-serif"
|
|
|
+ span.style.whiteSpace = 'nowrap'
|
|
|
+ span.textContent = text
|
|
|
+
|
|
|
+ // 应用额外样式
|
|
|
+ Object.keys(extraStyles).forEach(key => {
|
|
|
+ span.style[key as any] = extraStyles[key];
|
|
|
+ });
|
|
|
+
|
|
|
+ document.body.appendChild(span)
|
|
|
+ const width = span.offsetWidth
|
|
|
+ document.body.removeChild(span)
|
|
|
+
|
|
|
+ return width
|
|
|
+};
|
|
|
+
|
|
|
+// 自定义日期时间格式化函数
|
|
|
+const formatDateTime = (dateString: string | Date) => {
|
|
|
+ if (!dateString) return '';
|
|
|
+
|
|
|
+ const date = new Date(dateString);
|
|
|
+
|
|
|
+ // 确保日期有效
|
|
|
+ if (isNaN(date.getTime())) {
|
|
|
+ return String(dateString).replace(/[\r\n]/g, '');;
|
|
|
+ }
|
|
|
+
|
|
|
+ const year = date.getFullYear();
|
|
|
+ const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
|
+ const day = String(date.getDate()).padStart(2, '0');
|
|
|
+ const hours = String(date.getHours()).padStart(2, '0');
|
|
|
+ const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
|
+ const seconds = String(date.getSeconds()).padStart(2, '0');
|
|
|
+
|
|
|
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`.replace(/[\r\n]/g, '');
|
|
|
+};
|
|
|
+
|
|
|
+// 列宽计算函数
|
|
|
+const calculateColumnWidths = async () => {
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ if (!tableRef.value || !list.value.length) return
|
|
|
+
|
|
|
+ const table = tableRef.value
|
|
|
+ const columns = table.columns
|
|
|
+ const rows = list.value
|
|
|
+
|
|
|
+ // 获取表格容器宽度
|
|
|
+ const tableContainer = tableRef.value?.$el?.closest('.table-wrapper')
|
|
|
+ if (tableContainer) {
|
|
|
+ tableContainerWidth.value = tableContainer.clientWidth
|
|
|
+ }
|
|
|
+
|
|
|
+ // 计算各列所需最小宽度
|
|
|
+ const columnMinWidths = columns.map((col, colIndex) => {
|
|
|
+ if (colIndex === 0) return 60 // 选择列固定宽度
|
|
|
+
|
|
|
+ // 测量表头宽度
|
|
|
+ // 测量表头宽度 - 使用表头实际样式
|
|
|
+ const headerWidth = col.label
|
|
|
+ ? measureText(col.label, '14px', 'bold', {
|
|
|
+ padding: '0 12px', // 表头实际内边距
|
|
|
+ boxSizing: 'border-box'
|
|
|
+ }) + 0 // 安全边距
|
|
|
+ : 0;
|
|
|
+
|
|
|
+ // 测量单元格内容宽度
|
|
|
+ let maxCellWidth = 0
|
|
|
+ rows.forEach(row => {
|
|
|
+ let cellValue = ''
|
|
|
+ let cellWidth = 0
|
|
|
+ if (col.property === 'createTime') {
|
|
|
+ // 特殊处理:使用格式化后的日期文本
|
|
|
+ cellValue = formatDateTime(row[col.property])
|
|
|
+ // 使用完整时间样本确保宽度足够
|
|
|
+ const sampleText = '2024-12-31 23:59:59';
|
|
|
+ const sampleWidth = measureText(sampleText, '14px', 'normal', {
|
|
|
+ padding: '0 12px',
|
|
|
+ boxSizing: 'border-box'
|
|
|
+ });
|
|
|
+ // 时间列额外增加安全边距
|
|
|
+ cellWidth = Math.max(
|
|
|
+ measureText(cellValue, '14px', 'normal', {
|
|
|
+ padding: '0 12px',
|
|
|
+ boxSizing: 'border-box'
|
|
|
+ }),
|
|
|
+ sampleWidth
|
|
|
+ ) + 0; // 安全边距
|
|
|
+ // if (cellWidth > maxCellWidth) maxCellWidth = cellWidth
|
|
|
+ } else if (col.property === 'deviceStatus') {
|
|
|
+ // 特殊处理:字典标签文本
|
|
|
+ const statusText = row.deviceStatusLabel || row[col.property] || '';
|
|
|
+ // 模拟el-tag样式进行测量
|
|
|
+ cellWidth = measureText(statusText, '12px', 'normal', {
|
|
|
+ padding: '2px 7px',
|
|
|
+ border: '1px solid #dcdfe6',
|
|
|
+ borderRadius: '4px',
|
|
|
+ display: 'inline-block',
|
|
|
+ lineHeight: '1.5',
|
|
|
+ boxSizing: 'border-box'
|
|
|
+ }) + 0; // 20px安全边距
|
|
|
+ } else {
|
|
|
+ cellValue = row[col.property] || ''
|
|
|
+ cellWidth = measureText(cellValue, '14px', 'normal', {
|
|
|
+ padding: '0 12px',
|
|
|
+ boxSizing: 'border-box'
|
|
|
+ }) + 0; // 安全边距
|
|
|
+ }
|
|
|
+ if (cellWidth > maxCellWidth) maxCellWidth = cellWidth
|
|
|
+ })
|
|
|
+
|
|
|
+ // 取标题和内容的最大值,并设置最小宽度
|
|
|
+ let minWidth = 100; // 默认最小宽度
|
|
|
+ if (col.property === 'createTime') {
|
|
|
+ minWidth = 100; // 时间列最小宽度设为180px
|
|
|
+ }
|
|
|
+ // 取标题和内容的最大值
|
|
|
+ return Math.max(headerWidth, maxCellWidth, minWidth)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 记录弹性列的最小宽度
|
|
|
+ flexColumnMinWidths.deviceCode = columnMinWidths[1]
|
|
|
+ flexColumnMinWidths.deviceName = columnMinWidths[2]
|
|
|
+ flexColumnMinWidths.deptName = columnMinWidths[4]
|
|
|
+ flexColumnMinWidths.deviceStatus = columnMinWidths[5]
|
|
|
+ flexColumnMinWidths.createTime = columnMinWidths[6]
|
|
|
+
|
|
|
+ // 触发表格重新布局
|
|
|
+ table.doLayout()
|
|
|
+};
|
|
|
+
|
|
|
const getList = async () => {
|
|
|
loading.value = true
|
|
|
try {
|
|
@@ -177,8 +338,12 @@ const getList = async () => {
|
|
|
// 数据加载完成后重新计算高度
|
|
|
await nextTick();
|
|
|
calculateTableHeight();
|
|
|
+ calculateColumnWidths()
|
|
|
} finally {
|
|
|
loading.value = false
|
|
|
+ // 数据加载完成后计算列宽
|
|
|
+ await nextTick();
|
|
|
+ calculateColumnWidths();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -292,21 +457,25 @@ const resetQuery = () => {
|
|
|
// 监听列表变化动态调整高度
|
|
|
watch(list, () => {
|
|
|
calculateTableHeight();
|
|
|
+ if (dialogVisible.value) {
|
|
|
+ calculateColumnWidths();
|
|
|
+ }
|
|
|
});
|
|
|
|
|
|
// 监听窗口大小变化
|
|
|
onMounted(() => {
|
|
|
window.addEventListener('resize', calculateTableHeight);
|
|
|
+ window.addEventListener('resize', calculateColumnWidths);
|
|
|
});
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
window.removeEventListener('resize', calculateTableHeight);
|
|
|
+ window.removeEventListener('resize', calculateColumnWidths);
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
-/* 新增样式 */
|
|
|
.device-select-dialog {
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
@@ -334,16 +503,22 @@ onUnmounted(() => {
|
|
|
|
|
|
/* 列宽度保证 - 防止挤压 */
|
|
|
.el-table {
|
|
|
- ::v-deep(.el-table__cell) {
|
|
|
- min-width: 80px;
|
|
|
+ /* 确保所有列头文字居中 */
|
|
|
+ ::v-deep(.el-table__header) th > .cell {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
|
|
|
- &:first-child {
|
|
|
- min-width: 60px;
|
|
|
- }
|
|
|
+ /* 所有内容列居中对齐 */
|
|
|
+ ::v-deep(.el-table__body) td {
|
|
|
+ text-align: center !important;
|
|
|
|
|
|
- &:nth-child(2),
|
|
|
- &:nth-child(3) {
|
|
|
- min-width: 120px;
|
|
|
+ .cell {
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -353,6 +528,80 @@ onUnmounted(() => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/* 列宽自适应样式 */
|
|
|
+::v-deep(.el-table) {
|
|
|
+ .el-table__header th {
|
|
|
+ padding: 0 !important;
|
|
|
+ .cell {
|
|
|
+ padding: 0 0px !important;
|
|
|
+ box-sizing: border-box !important;
|
|
|
+ font-weight: bold !important;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-table__body td {
|
|
|
+ padding: 0 !important;
|
|
|
+ .cell {
|
|
|
+ padding: 0 0px !important;
|
|
|
+ box-sizing: border-box !important;
|
|
|
+ display: flex;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 特定列额外修正 */
|
|
|
+ .el-table__cell:nth-child(4), /* 部门列 */
|
|
|
+ .el-table__cell:nth-child(5), /* 状态列 */
|
|
|
+ .el-table__cell:nth-child(6) /* 时间列 */ {
|
|
|
+ .date-cell {
|
|
|
+ white-space: nowrap !important;
|
|
|
+ overflow: visible !important;
|
|
|
+ text-overflow: clip !important;
|
|
|
+ justify-content: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 固定表格布局 */
|
|
|
+.fixed-layout-table {
|
|
|
+ ::v-deep(table) {
|
|
|
+ table-layout: fixed !important; /* 固定列宽 */
|
|
|
+ width: auto !important;
|
|
|
+ min-width: 100%;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.el-table__header),
|
|
|
+ ::v-deep(.el-table__body) {
|
|
|
+ width: auto !important; /* 允许宽度扩展 */
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep(.el-table__cell) {
|
|
|
+ overflow: visible !important; /* 禁用裁剪 */
|
|
|
+ text-overflow: unset !important; /* 移除省略号 */
|
|
|
+ white-space: nowrap !important; /* 禁止换行 */
|
|
|
+
|
|
|
+ &:nth-child(4) { /* 部门 */
|
|
|
+ min-width: v-bind('flexColumnMinWidths.deptName + "px"');
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ &:nth-child(5) { /* 状态 */
|
|
|
+ min-width: v-bind('flexColumnMinWidths.deviceStatus + "px"');
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ &:nth-child(6) { /* 创建时间 */
|
|
|
+ min-width: v-bind('(flexColumnMinWidths.createTime) + "px"');
|
|
|
+ overflow: visible !important;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
.dialog-top {
|
|
|
flex-shrink: 0;
|
|
|
margin-bottom: 15px;
|
|
@@ -370,19 +619,20 @@ onUnmounted(() => {
|
|
|
max-height: 100%;
|
|
|
|
|
|
.table-wrapper {
|
|
|
- overflow: visible !important;
|
|
|
+ overflow: auto !important;
|
|
|
.el-table {
|
|
|
// 表格自带的滚动机制
|
|
|
::v-deep(.el-table__body-wrapper) {
|
|
|
- overflow-y: auto !important;
|
|
|
+ overflow: auto !important;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.table-wrapper {
|
|
|
- flex: 1;
|
|
|
- overflow-y: auto; /* 内部滚动 */
|
|
|
+ width: 100%;
|
|
|
+ overflow-y: hidden;
|
|
|
+ overflow-x: auto !important;
|
|
|
}
|
|
|
|
|
|
.no-label-radio .el-radio__label {
|