|
@@ -71,85 +71,81 @@
|
|
</ContentWrap>
|
|
</ContentWrap>
|
|
|
|
|
|
<!-- 列表 -->
|
|
<!-- 列表 -->
|
|
- <ContentWrap>
|
|
|
|
- <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
|
|
|
- <el-table-column :label="t('iotDevice.serial')" width="70" align="center">
|
|
|
|
- <template #default="scope">
|
|
|
|
- {{ scope.$index + 1 }}
|
|
|
|
- </template>
|
|
|
|
- </el-table-column>
|
|
|
|
- <el-table-column label="客户名称" align="center" prop="manufactureName" />
|
|
|
|
- <el-table-column label="合同名称" align="center" prop="contractName" >
|
|
|
|
- <template #default="scope">
|
|
|
|
- <el-link type="primary" @click="showTaskList(scope.row)">
|
|
|
|
- {{ scope.row.contractName }}
|
|
|
|
- </el-link>
|
|
|
|
- </template>
|
|
|
|
- </el-table-column>
|
|
|
|
- <el-table-column label="合同编号" align="center" prop="contractCode" />
|
|
|
|
- <el-table-column label="工作量" align="center">
|
|
|
|
- <el-table-column label="总数" align="center" prop="workloadTotal" />
|
|
|
|
- <el-table-column label="完成" align="center" prop="workloadFinish" />
|
|
|
|
- </el-table-column>
|
|
|
|
- <el-table-column label="合同起止时间" align="center">
|
|
|
|
|
|
+ <ContentWrap ref="tableContainerRef">
|
|
|
|
+ <div class="table-container">
|
|
|
|
+ <el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" style="width: 100%" :cell-style="{padding: '5px'}">
|
|
|
|
+ <el-table-column :label="t('iotDevice.serial')" :width="columnWidths.serial" align="center" v-if="false">
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ {{ scope.$index + 1 }}
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column label="客户名称" align="left" prop="manufactureName" :width="columnWidths.manufactureName" />
|
|
|
|
+ <el-table-column label="合同名称" align="center" prop="contractName" :width="columnWidths.contractName" >
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <el-link type="primary" @click="showTaskList(scope.row)">
|
|
|
|
+ {{ scope.row.contractName }}
|
|
|
|
+ </el-link>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column label="合同编号" align="center" prop="contractCode" :width="columnWidths.contractCode" />
|
|
|
|
+ <el-table-column label="总工作量" align="center" prop="workloadTotal" :width="columnWidths.workloadTotal" />
|
|
|
|
+ <el-table-column label="已完成工作量" align="center" prop="workloadFinish" :width="columnWidths.workloadFinish" />
|
|
<el-table-column
|
|
<el-table-column
|
|
- label="开始时间"
|
|
|
|
|
|
+ label="合同开始时间"
|
|
align="center"
|
|
align="center"
|
|
prop="startTime"
|
|
prop="startTime"
|
|
:formatter="dateFormatter2"
|
|
:formatter="dateFormatter2"
|
|
- width="180px"
|
|
|
|
|
|
+ :width="columnWidths.startTime"
|
|
/>
|
|
/>
|
|
<el-table-column
|
|
<el-table-column
|
|
- label="完成时间"
|
|
|
|
|
|
+ label="合同完成时间"
|
|
align="center"
|
|
align="center"
|
|
prop="endTime"
|
|
prop="endTime"
|
|
:formatter="dateFormatter2"
|
|
:formatter="dateFormatter2"
|
|
- width="180px"
|
|
|
|
|
|
+ :width="columnWidths.endTime"
|
|
/>
|
|
/>
|
|
- </el-table-column>
|
|
|
|
-<!-- <el-table-column label="施工地点" align="center" prop="location" />
|
|
|
|
- <el-table-column label="施工工艺" align="center" prop="technique" />-->
|
|
|
|
- <el-table-column :label="t('project.payment')" align="center" prop="payment" min-width="90">
|
|
|
|
- <template #default="scope">
|
|
|
|
- <dict-tag :type="DICT_TYPE.PMS_PROJECT_SETTLEMENT" :value="scope.row.payment" />
|
|
|
|
- </template>
|
|
|
|
- </el-table-column>
|
|
|
|
- <el-table-column
|
|
|
|
- label="创建时间"
|
|
|
|
- align="center"
|
|
|
|
- prop="createTime"
|
|
|
|
- :formatter="dateFormatter"
|
|
|
|
- width="180px"
|
|
|
|
- />
|
|
|
|
- <el-table-column label="操作" align="center" min-width="180px">
|
|
|
|
- <template #default="scope">
|
|
|
|
- <el-button
|
|
|
|
- link
|
|
|
|
- type="primary"
|
|
|
|
- @click="openForm('update', scope.row.id)"
|
|
|
|
- v-hasPermi="['rq:iot-project-info:update']"
|
|
|
|
- >
|
|
|
|
- 编辑
|
|
|
|
- </el-button>
|
|
|
|
- <el-button
|
|
|
|
- link
|
|
|
|
- type="primary"
|
|
|
|
- @click="assignTask(scope.row)"
|
|
|
|
- v-hasPermi="['rq:iot-project-task:create']"
|
|
|
|
- >
|
|
|
|
- 分配任务
|
|
|
|
- </el-button>
|
|
|
|
- <el-button
|
|
|
|
- link
|
|
|
|
- type="danger"
|
|
|
|
- @click="handleDelete(scope.row.id)"
|
|
|
|
- v-hasPermi="['rq:iot-project-info:delete']"
|
|
|
|
- >
|
|
|
|
- 删除
|
|
|
|
- </el-button>
|
|
|
|
- </template>
|
|
|
|
- </el-table-column>
|
|
|
|
- </el-table>
|
|
|
|
|
|
+ <el-table-column :label="t('project.payment')" align="center" prop="payment" :width="columnWidths.payment">
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <dict-tag :type="DICT_TYPE.PMS_PROJECT_SETTLEMENT" :value="scope.row.payment" />
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column
|
|
|
|
+ label="创建时间"
|
|
|
|
+ align="center"
|
|
|
|
+ prop="createTime"
|
|
|
|
+ :formatter="dateFormatter"
|
|
|
|
+ :width="columnWidths.createTime"
|
|
|
|
+ />
|
|
|
|
+ <el-table-column label="操作" align="center" :width="columnWidths.operation" fixed="right">
|
|
|
|
+ <template #default="scope">
|
|
|
|
+ <el-button
|
|
|
|
+ link
|
|
|
|
+ type="primary"
|
|
|
|
+ @click="openForm('update', scope.row.id)"
|
|
|
|
+ v-hasPermi="['rq:iot-project-info:update']"
|
|
|
|
+ >
|
|
|
|
+ 编辑
|
|
|
|
+ </el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ link
|
|
|
|
+ type="primary"
|
|
|
|
+ @click="assignTask(scope.row)"
|
|
|
|
+ v-hasPermi="['rq:iot-project-task:create']"
|
|
|
|
+ >
|
|
|
|
+ 分配任务
|
|
|
|
+ </el-button>
|
|
|
|
+ <el-button
|
|
|
|
+ link
|
|
|
|
+ type="danger"
|
|
|
|
+ @click="handleDelete(scope.row.id)"
|
|
|
|
+ v-hasPermi="['rq:iot-project-info:delete']"
|
|
|
|
+ >
|
|
|
|
+ 删除
|
|
|
|
+ </el-button>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ </el-table>
|
|
|
|
+ </div>
|
|
<!-- 分页 -->
|
|
<!-- 分页 -->
|
|
<Pagination
|
|
<Pagination
|
|
:total="total"
|
|
:total="total"
|
|
@@ -182,12 +178,6 @@
|
|
<dict-tag :type="DICT_TYPE.PMS_PROJECT_WELL_CATEGORY" :value="scope.row.wellCategory" />
|
|
<dict-tag :type="DICT_TYPE.PMS_PROJECT_WELL_CATEGORY" :value="scope.row.wellCategory" />
|
|
</template>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table-column>
|
|
- <!--
|
|
|
|
- <el-table-column :label="t('project.status')" align="center" prop="status" min-width="70">
|
|
|
|
- <template #default="scope">
|
|
|
|
- <dict-tag :type="DICT_TYPE.PMS_PROJECT_TASK_SCHEDULE" :value="scope.row.status" />
|
|
|
|
- </template>
|
|
|
|
- </el-table-column> -->
|
|
|
|
<el-table-column :label="t('project.status')" align="center" prop="status" min-width="70">
|
|
<el-table-column :label="t('project.status')" align="center" prop="status" min-width="70">
|
|
<template #default="scope">
|
|
<template #default="scope">
|
|
<el-link type="primary" @click="openTimelineDialog(scope.row)">
|
|
<el-link type="primary" @click="openTimelineDialog(scope.row)">
|
|
@@ -279,8 +269,7 @@ import * as DeptApi from "@/api/system/dept"; // 引入部门API
|
|
import { handleTree } from "@/utils/tree"; // 引入树形处理工具
|
|
import { handleTree } from "@/utils/tree"; // 引入树形处理工具
|
|
import { IotProjectTaskScheduleApi } from '@/api/pms/iotprojecttaskschedule'
|
|
import { IotProjectTaskScheduleApi } from '@/api/pms/iotprojecttaskschedule'
|
|
import dayjs from 'dayjs' // 引入 dayjs 用于时间格式化
|
|
import dayjs from 'dayjs' // 引入 dayjs 用于时间格式化
|
|
-import { ref, reactive, onMounted, computed, nextTick } from 'vue'
|
|
|
|
-
|
|
|
|
|
|
+import { ref, reactive, onMounted, computed, nextTick, watch } from 'vue'
|
|
|
|
|
|
/** 项目信息 列表 */
|
|
/** 项目信息 列表 */
|
|
defineOptions({ name: 'iotProjectInfo' })
|
|
defineOptions({ name: 'iotProjectInfo' })
|
|
@@ -304,6 +293,11 @@ const currentTaskRow = ref<any>(null) // 当前选中的任务行数据
|
|
const stepsData = ref<Array<{title: string, description?: string, status?: string}>>([]) // 步骤数据
|
|
const stepsData = ref<Array<{title: string, description?: string, status?: string}>>([]) // 步骤数据
|
|
const currentStepIndex = ref(0) // 当前步骤索引
|
|
const currentStepIndex = ref(0) // 当前步骤索引
|
|
|
|
|
|
|
|
+// 表格引用
|
|
|
|
+const tableRef = ref()
|
|
|
|
+// 表格容器引用
|
|
|
|
+const tableContainerRef = ref()
|
|
|
|
+
|
|
const loading = ref(true) // 列表的加载中
|
|
const loading = ref(true) // 列表的加载中
|
|
const list = ref<IotProjectInfoVO[]>([]) // 列表的数据
|
|
const list = ref<IotProjectInfoVO[]>([]) // 列表的数据
|
|
const total = ref(0) // 列表的总页数
|
|
const total = ref(0) // 列表的总页数
|
|
@@ -328,6 +322,39 @@ const queryParams = reactive({
|
|
const queryFormRef = ref() // 搜索的表单
|
|
const queryFormRef = ref() // 搜索的表单
|
|
const exportLoading = ref(false) // 导出的加载中
|
|
const exportLoading = ref(false) // 导出的加载中
|
|
const { push } = useRouter() // 路由跳转
|
|
const { push } = useRouter() // 路由跳转
|
|
|
|
+
|
|
|
|
+// 列宽度配置
|
|
|
|
+const columnWidths = ref({
|
|
|
|
+ serial: '50px',
|
|
|
|
+ manufactureName: '120px',
|
|
|
|
+ contractName: '150px',
|
|
|
|
+ contractCode: '120px',
|
|
|
|
+ workloadTotal: '100px',
|
|
|
|
+ workloadFinish: '120px',
|
|
|
|
+ startTime: '150px',
|
|
|
|
+ endTime: '150px',
|
|
|
|
+ payment: '100px',
|
|
|
|
+ createTime: '150px',
|
|
|
|
+ operation: '200px'
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+// 计算文本宽度
|
|
|
|
+const getTextWidth = (text: string, fontSize = 14) => {
|
|
|
|
+ const span = document.createElement('span');
|
|
|
|
+ span.style.visibility = 'hidden';
|
|
|
|
+ span.style.position = 'absolute';
|
|
|
|
+ span.style.whiteSpace = 'nowrap';
|
|
|
|
+ span.style.fontSize = `${fontSize}px`;
|
|
|
|
+ span.style.fontFamily = 'inherit';
|
|
|
|
+ span.innerText = text;
|
|
|
|
+
|
|
|
|
+ document.body.appendChild(span);
|
|
|
|
+ const width = span.offsetWidth;
|
|
|
|
+ document.body.removeChild(span);
|
|
|
|
+
|
|
|
|
+ return width;
|
|
|
|
+};
|
|
|
|
+
|
|
/** 查询列表 */
|
|
/** 查询列表 */
|
|
const getList = async () => {
|
|
const getList = async () => {
|
|
loading.value = true
|
|
loading.value = true
|
|
@@ -342,6 +369,8 @@ const getList = async () => {
|
|
// 使用 nextTick 确保 DOM 更新后再执行选中操作
|
|
// 使用 nextTick 确保 DOM 更新后再执行选中操作
|
|
nextTick(() => {
|
|
nextTick(() => {
|
|
showTaskList(list.value[0]);
|
|
showTaskList(list.value[0]);
|
|
|
|
+ // 计算列宽
|
|
|
|
+ calculateColumnWidths();
|
|
});
|
|
});
|
|
} else {
|
|
} else {
|
|
// 如果没有数据,确保任务列表区域关闭
|
|
// 如果没有数据,确保任务列表区域关闭
|
|
@@ -353,6 +382,90 @@ const getList = async () => {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// 计算列宽度
|
|
|
|
+const calculateColumnWidths = () => {
|
|
|
|
+ const MIN_WIDTH = 80; // 最小列宽
|
|
|
|
+ const PADDING = 25; // 列内边距
|
|
|
|
+ const FLEXIBLE_COLUMNS = ['manufactureName', 'contractName', 'contractCode']; // 可伸缩列
|
|
|
|
+
|
|
|
|
+ // 确保表格容器存在
|
|
|
|
+ if (!tableContainerRef.value?.$el) return;
|
|
|
|
+
|
|
|
|
+ const container = tableContainerRef.value.$el;
|
|
|
|
+ const containerWidth = container.clientWidth;
|
|
|
|
+
|
|
|
|
+ // 1. 计算所有列的最小宽度
|
|
|
|
+ const minWidths: Record<string, number> = {};
|
|
|
|
+ let totalMinWidth = 0;
|
|
|
|
+
|
|
|
|
+ // 计算列最小宽度的函数
|
|
|
|
+ const calculateColumnMinWidth = (key: string, label: string, getValue: Function) => {
|
|
|
|
+ const headerWidth = getTextWidth(label) * 1.2;
|
|
|
|
+ let contentMaxWidth = 0;
|
|
|
|
+
|
|
|
|
+ // 计算内容最大宽度
|
|
|
|
+ list.value.forEach((row, index) => {
|
|
|
|
+ const text = String(getValue ? getValue(row, index) : (row[key] || ''));
|
|
|
|
+ const textWidth = getTextWidth(text);
|
|
|
|
+ if (textWidth > contentMaxWidth) contentMaxWidth = textWidth;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ const minWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
|
|
|
|
+ minWidths[key] = minWidth;
|
|
|
|
+ totalMinWidth += minWidth;
|
|
|
|
+ return minWidth;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ // 计算各列最小宽度
|
|
|
|
+ calculateColumnMinWidth('serial', t('iotDevice.serial'), (row: any, index: number) => `${index + 1}`);
|
|
|
|
+ calculateColumnMinWidth('manufactureName', '客户名称', (row: any) => row.manufactureName);
|
|
|
|
+ calculateColumnMinWidth('contractName', '合同名称', (row: any) => row.contractName);
|
|
|
|
+ calculateColumnMinWidth('contractCode', '合同编号', (row: any) => row.contractCode);
|
|
|
|
+ calculateColumnMinWidth('workloadTotal', '总工作量', (row: any) => row.workloadTotal);
|
|
|
|
+ calculateColumnMinWidth('workloadFinish', '已完成工作量', (row: any) => row.workloadFinish);
|
|
|
|
+ calculateColumnMinWidth('startTime', '合同开始时间', (row: any) => dateFormatter2(null, null, row.startTime));
|
|
|
|
+ calculateColumnMinWidth('endTime', '合同完成时间', (row: any) => dateFormatter2(null, null, row.endTime));
|
|
|
|
+ calculateColumnMinWidth('payment', t('project.payment'), (row: any) => {
|
|
|
|
+ const dict = getIntDictOptions(DICT_TYPE.PMS_PROJECT_SETTLEMENT)
|
|
|
|
+ .find(d => d.value === row.payment);
|
|
|
|
+ return dict ? dict.label : '';
|
|
|
|
+ });
|
|
|
|
+ calculateColumnMinWidth('createTime', '创建时间', (row: any) => dateFormatter(null, null, row.createTime));
|
|
|
|
+
|
|
|
|
+ // 操作列固定宽度
|
|
|
|
+ minWidths.operation = 200;
|
|
|
|
+ totalMinWidth += 200;
|
|
|
|
+
|
|
|
|
+ // 2. 计算可伸缩列最终宽度
|
|
|
|
+ const newWidths: Record<string, string> = {};
|
|
|
|
+ const availableWidth = containerWidth - 17; // 减去滚动条宽度
|
|
|
|
+
|
|
|
|
+ // 应用最小宽度到所有列
|
|
|
|
+ Object.keys(minWidths).forEach(key => {
|
|
|
|
+ newWidths[key] = `${minWidths[key]}px`;
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // 计算可伸缩列需要的宽度
|
|
|
|
+ if (totalMinWidth < availableWidth) {
|
|
|
|
+ // 有剩余空间:按比例分配给可伸缩列
|
|
|
|
+ const extraSpace = availableWidth - totalMinWidth;
|
|
|
|
+ const flexibleColumnCount = FLEXIBLE_COLUMNS.length;
|
|
|
|
+ const spacePerColumn = Math.floor(extraSpace / flexibleColumnCount);
|
|
|
|
+
|
|
|
|
+ FLEXIBLE_COLUMNS.forEach(key => {
|
|
|
|
+ newWidths[key] = `${minWidths[key] + spacePerColumn}px`;
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 3. 更新列宽配置
|
|
|
|
+ columnWidths.value = newWidths;
|
|
|
|
+
|
|
|
|
+ // 4. 触发表格重新布局
|
|
|
|
+ nextTick(() => {
|
|
|
|
+ tableRef.value?.doLayout();
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
/** 搜索按钮操作 */
|
|
/** 搜索按钮操作 */
|
|
const handleQuery = () => {
|
|
const handleQuery = () => {
|
|
queryParams.pageNo = 1
|
|
queryParams.pageNo = 1
|
|
@@ -711,13 +824,47 @@ const handleExport = async () => {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// 声明 ResizeObserver 实例
|
|
|
|
+let resizeObserver: ResizeObserver | null = null;
|
|
|
|
+
|
|
/** 初始化 **/
|
|
/** 初始化 **/
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
deptList.value = handleTree(await DeptApi.companyLevelChildrenDepts());
|
|
deptList.value = handleTree(await DeptApi.companyLevelChildrenDepts());
|
|
getList()
|
|
getList()
|
|
// 预加载任务进度字典
|
|
// 预加载任务进度字典
|
|
getTaskScheduleDictOptions()
|
|
getTaskScheduleDictOptions()
|
|
|
|
+
|
|
|
|
+ // 创建 ResizeObserver 监听表格容器尺寸变化
|
|
|
|
+ if (tableContainerRef.value?.$el) {
|
|
|
|
+ resizeObserver = new ResizeObserver(() => {
|
|
|
|
+ // 使用防抖避免频繁触发
|
|
|
|
+ clearTimeout((window as any).resizeTimer);
|
|
|
|
+ (window as any).resizeTimer = setTimeout(() => {
|
|
|
|
+ calculateColumnWidths();
|
|
|
|
+ }, 100);
|
|
|
|
+ });
|
|
|
|
+ resizeObserver.observe(tableContainerRef.value.$el);
|
|
|
|
+ }
|
|
|
|
+})
|
|
|
|
+
|
|
|
|
+onUnmounted(() => {
|
|
|
|
+ // 清除 ResizeObserver
|
|
|
|
+ if (resizeObserver && tableContainerRef.value?.$el) {
|
|
|
|
+ resizeObserver.unobserve(tableContainerRef.value.$el);
|
|
|
|
+ resizeObserver = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // 清除定时器
|
|
|
|
+ if ((window as any).resizeTimer) {
|
|
|
|
+ clearTimeout((window as any).resizeTimer);
|
|
|
|
+ }
|
|
})
|
|
})
|
|
|
|
+
|
|
|
|
+// 监听列表数据变化重新计算列宽
|
|
|
|
+watch(list, () => {
|
|
|
|
+ nextTick(calculateColumnWidths)
|
|
|
|
+}, { deep: true })
|
|
|
|
+
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|
|
@@ -785,4 +932,36 @@ onMounted(async () => {
|
|
overflow-x: auto;
|
|
overflow-x: auto;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* 表格容器样式,确保水平滚动 */
|
|
|
|
+.table-container {
|
|
|
|
+ width: 100%;
|
|
|
|
+ overflow-x: auto;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 确保表格单元格内容不换行 */
|
|
|
|
+:deep(.el-table .cell) {
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 确保表格列标题不换行 */
|
|
|
|
+:deep(.el-table th > .cell) {
|
|
|
|
+ white-space: nowrap;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 调整表格最小宽度,确保内容完全显示 */
|
|
|
|
+:deep(.el-table) {
|
|
|
|
+ min-width: 100%;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/* 强制显示所有内容,防止省略号 */
|
|
|
|
+:deep(.el-table td.el-table__cell),
|
|
|
|
+:deep(.el-table th.el-table__cell) {
|
|
|
|
+ overflow: visible !important;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+:deep(.el-table .cell) {
|
|
|
|
+ overflow: visible !important;
|
|
|
|
+ text-overflow: clip !important;
|
|
|
|
+}
|
|
|
|
+
|
|
</style>
|
|
</style>
|