|
@@ -18,18 +18,7 @@
|
|
|
/>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
- <!--
|
|
|
- <el-form-item label="库存地点" prop="storageLocationId">
|
|
|
- <el-select v-model="queryParams.storageLocationId" clearable placeholder="请选择" class="!w-240px">
|
|
|
- <el-option
|
|
|
- v-for="item in storageLocationList"
|
|
|
- :key="item.id"
|
|
|
- :label="item.storageLocationName"
|
|
|
- :value="item.id!"
|
|
|
- />
|
|
|
- </el-select>
|
|
|
- </el-form-item>
|
|
|
- -->
|
|
|
+
|
|
|
<el-form-item :label="t('workOrderMaterial.costCenter')" prop="costCenterId" v-if="!shouldHideComponents">
|
|
|
<el-select v-model="queryParams.costCenterId" clearable filterable :placeholder="t('faultForm.choose')" class="!w-240px">
|
|
|
<el-option
|
|
@@ -110,35 +99,25 @@
|
|
|
</ContentWrap>
|
|
|
|
|
|
<!-- 列表 -->
|
|
|
- <ContentWrap>
|
|
|
- <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
|
|
|
- <el-table-column :label="t('workOrderMaterial.factory')" align="center" prop="factory" />
|
|
|
- <el-table-column :label="t('workOrderMaterial.costCenter')" align="center" prop="costCenter" />
|
|
|
- <el-table-column :label="t('chooseMaintain.materialCode')" align="center" prop="materialCode" />
|
|
|
- <el-table-column :label="t('chooseMaintain.materialName')" align="center" prop="materialName" />
|
|
|
- <el-table-column :label="t('route.quantity')" align="center" prop="quantity" :formatter="erpPriceTableColumnFormatter" />
|
|
|
- <el-table-column :label="t('workOrderMaterial.unitPrice')" align="center" prop="unitPrice" :formatter="erpPriceTableColumnFormatter" />
|
|
|
- <el-table-column :label="t('workOrderMaterial.unit')" align="center" prop="unit" />
|
|
|
+ <ContentWrap ref="tableContainerRef" class="table-container">
|
|
|
+ <el-table ref="tableRef" v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="false" style="width: 100%">
|
|
|
+ <el-table-column :label="t('workOrderMaterial.factory')" align="center" prop="factory" :width="columnWidths.factory"/>
|
|
|
+ <el-table-column :label="t('workOrderMaterial.costCenter')" align="center" prop="costCenter" :width="columnWidths.costCenter"/>
|
|
|
+ <el-table-column :label="t('chooseMaintain.materialCode')" align="center" prop="materialCode" :width="columnWidths.materialCode"/>
|
|
|
+ <el-table-column :label="t('chooseMaintain.materialName')" align="left" prop="materialName" :width="columnWidths.materialName"/>
|
|
|
+ <el-table-column :label="t('route.quantity')" align="center" prop="quantity"
|
|
|
+ :formatter="erpPriceTableColumnFormatter" :width="columnWidths.quantity"/>
|
|
|
+ <el-table-column :label="t('workOrderMaterial.unitPrice')" align="center" prop="unitPrice"
|
|
|
+ :formatter="erpPriceTableColumnFormatter" :width="columnWidths.unitPrice"/>
|
|
|
+ <el-table-column :label="t('workOrderMaterial.unit')" align="center" prop="unit" :width="columnWidths.unit"/>
|
|
|
<el-table-column
|
|
|
:label="t('stock.storageTime')"
|
|
|
align="center"
|
|
|
prop="storageTime"
|
|
|
:formatter="dateFormatter"
|
|
|
- width="180px"
|
|
|
+ :width="columnWidths.storageTime"
|
|
|
/>
|
|
|
- <!--
|
|
|
- <el-table-column label="操作" align="center" min-width="120px">
|
|
|
- <template #default="scope">
|
|
|
- <el-button
|
|
|
- link
|
|
|
- type="primary"
|
|
|
- @click="openForm('update', scope.row.id)"
|
|
|
- v-hasPermi="['pms:iot-lock-stock:update']"
|
|
|
- >
|
|
|
- 编辑
|
|
|
- </el-button>
|
|
|
- </template>
|
|
|
- </el-table-column> -->
|
|
|
+
|
|
|
</el-table>
|
|
|
<!-- 分页 -->
|
|
|
<Pagination
|
|
@@ -160,9 +139,9 @@ import { IotLockStockApi, IotLockStockVO } from '@/api/pms/iotlockstock'
|
|
|
import IotLockStockForm from './IotLockStockForm.vue'
|
|
|
import {erpPriceTableColumnFormatter} from "@/utils";
|
|
|
import { useUserStore } from '@/store/modules/user'
|
|
|
-import {SapOrgApi, SapOrgVO} from "@/api/system/saporg";
|
|
|
+import { SapOrgApi, SapOrgVO } from "@/api/system/saporg";
|
|
|
import { checkRole } from '@/utils/permission'
|
|
|
-import { computed } from 'vue'
|
|
|
+import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
|
|
|
|
|
/** PMS 本地 库存 列表 */
|
|
|
defineOptions({ name: 'IotLockStock' })
|
|
@@ -209,10 +188,14 @@ const factoryList = ref([] as SapOrgVO[]) // 工厂列表
|
|
|
const storageLocationList = ref([] as SapOrgVO[]) // 库存地点列表
|
|
|
const costCenterList = ref([] as SapOrgVO[]) // SAP成本中心列表
|
|
|
|
|
|
-// 新增统计变量
|
|
|
+// 统计变量
|
|
|
const totalQuantity = ref(0) // 总数量
|
|
|
const totalAmount = ref(0) // 总金额
|
|
|
|
|
|
+// 表格容器和表格的引用
|
|
|
+const tableContainerRef = ref()
|
|
|
+const tableRef = ref()
|
|
|
+
|
|
|
const shouldHideComponents = computed(() => {
|
|
|
// 检查用户是否拥有 'A' 或 'B' 角色
|
|
|
return checkRole(['小队队长', '操作员'])
|
|
@@ -223,6 +206,142 @@ const selectedFactoryReqVO = ref({
|
|
|
factoryCodes: [] // 已经选择的SAP工厂code 列表
|
|
|
})
|
|
|
|
|
|
+// 列宽度配置
|
|
|
+const columnWidths = ref({
|
|
|
+ factory: '120px',
|
|
|
+ costCenter: '120px',
|
|
|
+ materialCode: '120px',
|
|
|
+ materialName: '200px', // 初始宽度,会被计算覆盖
|
|
|
+ quantity: '100px',
|
|
|
+ unitPrice: '100px',
|
|
|
+ unit: '100px',
|
|
|
+ storageTime: '180px'
|
|
|
+})
|
|
|
+
|
|
|
+/** 获取滚动条宽度 */
|
|
|
+const getScrollbarWidth = () => {
|
|
|
+ const outer = document.createElement('div');
|
|
|
+ outer.style.visibility = 'hidden';
|
|
|
+ outer.style.overflow = 'scroll';
|
|
|
+ document.body.appendChild(outer);
|
|
|
+
|
|
|
+ const inner = document.createElement('div');
|
|
|
+ outer.appendChild(inner);
|
|
|
+
|
|
|
+ const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
|
|
|
+ outer.parentNode?.removeChild(outer);
|
|
|
+
|
|
|
+ return scrollbarWidth;
|
|
|
+};
|
|
|
+
|
|
|
+/** 计算文本宽度 */
|
|
|
+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 calculateColumnWidths = () => {
|
|
|
+ const MIN_WIDTH = 80; // 最小列宽
|
|
|
+ const PADDING = 25; // 列内边距
|
|
|
+ const FLEXIBLE_COLUMN = 'materialName'; // 可伸缩列
|
|
|
+ const scrollbarWidth = getScrollbarWidth(); // 动态获取滚动条宽度
|
|
|
+
|
|
|
+ if (!tableContainerRef.value?.$el || list.value.length === 0) return;
|
|
|
+
|
|
|
+ const containerWidth = tableContainerRef.value.$el.clientWidth;
|
|
|
+
|
|
|
+ // 需要自适应的列配置
|
|
|
+ const autoColumns = [
|
|
|
+ { key: 'factory', label: t('workOrderMaterial.factory'), getValue: (row) => row.factory },
|
|
|
+ { key: 'costCenter', label: t('workOrderMaterial.costCenter'), getValue: (row) => row.costCenter },
|
|
|
+ { key: 'materialCode', label: t('chooseMaintain.materialCode'), getValue: (row) => row.materialCode },
|
|
|
+ { key: 'materialName', label: t('chooseMaintain.materialName'), getValue: (row) => row.materialName },
|
|
|
+ {
|
|
|
+ key: 'quantity',
|
|
|
+ label: t('route.quantity'),
|
|
|
+ getValue: (row) => erpPriceTableColumnFormatter(null, null, row.quantity, null)
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'unitPrice',
|
|
|
+ label: t('workOrderMaterial.unitPrice'),
|
|
|
+ getValue: (row) => erpPriceTableColumnFormatter(null, null, row.unitPrice, null)
|
|
|
+ },
|
|
|
+ { key: 'unit', label: t('workOrderMaterial.unit'), getValue: (row) => row.unit },
|
|
|
+ {
|
|
|
+ key: 'storageTime',
|
|
|
+ label: t('stock.storageTime'),
|
|
|
+ getValue: (row) => dateFormatter(null, null, row.storageTime)
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ const newWidths: Record<string, string> = {};
|
|
|
+ let totalFixedWidth = 0; // 所有固定列的总宽度
|
|
|
+
|
|
|
+ // 计算除可伸缩列外的所有列宽度
|
|
|
+ autoColumns.forEach(col => {
|
|
|
+ if (col.key === FLEXIBLE_COLUMN) return;
|
|
|
+
|
|
|
+ const headerText = col.label;
|
|
|
+ const headerWidth = getTextWidth(headerText) * 1.3; // 表头宽度(加粗效果增加20%)
|
|
|
+
|
|
|
+ // 计算内容最大宽度
|
|
|
+ let contentMaxWidth = 0;
|
|
|
+ list.value.forEach(row => {
|
|
|
+ const text = col.getValue ? String(col.getValue(row)) : String(row[col.key] || '');
|
|
|
+ const textWidth = getTextWidth(text);
|
|
|
+ if (textWidth > contentMaxWidth) contentMaxWidth = textWidth;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 取表头宽度、内容最大宽度和最小宽度的最大值
|
|
|
+ const finalWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
|
|
|
+ newWidths[col.key] = `${finalWidth}px`;
|
|
|
+ totalFixedWidth += finalWidth;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 处理可伸缩列(materialName)
|
|
|
+ const flexibleCol = autoColumns.find(col => col.key === FLEXIBLE_COLUMN);
|
|
|
+ if (flexibleCol) {
|
|
|
+ const headerText = flexibleCol.label;
|
|
|
+ const headerWidth = getTextWidth(headerText) * 1.3;
|
|
|
+
|
|
|
+ let contentMaxWidth = 0;
|
|
|
+ list.value.forEach(row => {
|
|
|
+ const text = flexibleCol.getValue ? String(flexibleCol.getValue(row)) : String(row[flexibleCol.key] || '');
|
|
|
+ const textWidth = getTextWidth(text);
|
|
|
+ if (textWidth > contentMaxWidth) contentMaxWidth = textWidth;
|
|
|
+ });
|
|
|
+
|
|
|
+ const baseWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING;
|
|
|
+
|
|
|
+ // 剩余空间 = 容器宽度 - 其他列总宽度 - 垂直滚动条宽度(17px)
|
|
|
+ const remainingWidth = containerWidth - totalFixedWidth - scrollbarWidth;
|
|
|
+
|
|
|
+ // 可伸缩列的宽度取剩余空间和基础宽度的最大值
|
|
|
+ const flexibleWidth = Math.max(remainingWidth, baseWidth);
|
|
|
+ newWidths[FLEXIBLE_COLUMN] = `${flexibleWidth}px`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新列宽度
|
|
|
+ columnWidths.value = newWidths;
|
|
|
+
|
|
|
+ // 重新布局表格
|
|
|
+ nextTick(() => {
|
|
|
+ tableRef.value?.doLayout();
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
/** 查询列表 */
|
|
|
const getList = async () => {
|
|
|
loading.value = true
|
|
@@ -240,6 +359,10 @@ const getList = async () => {
|
|
|
totalQuantity.value = 0
|
|
|
totalAmount.value = 0
|
|
|
}
|
|
|
+ // 数据加载完成后计算列宽
|
|
|
+ nextTick(() => {
|
|
|
+ calculateColumnWidths()
|
|
|
+ })
|
|
|
} finally {
|
|
|
loading.value = false
|
|
|
}
|
|
@@ -248,7 +371,7 @@ const getList = async () => {
|
|
|
await loadOrgData()
|
|
|
}
|
|
|
|
|
|
-// 新增:单独封装组织数据加载方法
|
|
|
+// 单独封装组织数据加载方法
|
|
|
const loadOrgData = async () => {
|
|
|
const deptId = useUserStore().getUser.deptId
|
|
|
if (typeof deptId === 'number' && !isNaN(deptId) && deptId > 0) {
|
|
@@ -364,7 +487,20 @@ const handleExport = async () => {
|
|
|
/** 初始化 **/
|
|
|
onMounted(() => {
|
|
|
getList()
|
|
|
+ // 添加窗口大小变化监听
|
|
|
+ window.addEventListener('resize', calculateColumnWidths)
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ // 移除窗口大小变化监听
|
|
|
+ window.removeEventListener('resize', calculateColumnWidths)
|
|
|
})
|
|
|
+
|
|
|
+// 监听列表数据变化,重新计算列宽
|
|
|
+watch(list, () => {
|
|
|
+ nextTick(calculateColumnWidths)
|
|
|
+}, { deep: true })
|
|
|
+
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
@@ -396,4 +532,50 @@ onMounted(() => {
|
|
|
font-weight: bold;
|
|
|
color: #409EFF;
|
|
|
}
|
|
|
+
|
|
|
+/* 表格容器样式 - 确保可以水平滚动 */
|
|
|
+.table-container {
|
|
|
+ overflow-x: auto;
|
|
|
+}
|
|
|
+
|
|
|
+/* 防止表格内容换行 */
|
|
|
+:deep(.el-table) .cell {
|
|
|
+ white-space: nowrap !important;
|
|
|
+ overflow: visible !important;
|
|
|
+ text-overflow: unset !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 确保表格行不换行 */
|
|
|
+:deep(.el-table__row) {
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/* 防止表格内容换行 */
|
|
|
+:deep(.el-table .cell) {
|
|
|
+ white-space: nowrap !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 表头特别处理 */
|
|
|
+:deep(.el-table__header) {
|
|
|
+ .cell {
|
|
|
+ display: inline-block;
|
|
|
+ white-space: nowrap;
|
|
|
+ width: auto !important;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/* 表格整体布局优化 */
|
|
|
+:deep(.el-table__inner-wrapper) {
|
|
|
+ min-width: 100% !important;
|
|
|
+ width: auto !important;
|
|
|
+}
|
|
|
+
|
|
|
+/* 单元格内容完全显示 */
|
|
|
+:deep(.el-table__body-wrapper) .el-table__cell .cell {
|
|
|
+ display: block;
|
|
|
+ overflow: visible;
|
|
|
+ text-overflow: unset;
|
|
|
+}
|
|
|
+
|
|
|
</style>
|