|
|
@@ -9,7 +9,14 @@
|
|
|
label-width="68px"
|
|
|
>
|
|
|
<el-form-item :label="t('workOrderMaterial.factory')" prop="factoryId">
|
|
|
- <el-select v-model="queryParams.factoryId" clearable filterable :placeholder="t('faultForm.choose')" class="!w-240px" @change="selectedFactoryChange">
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.factoryId"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ :placeholder="t('faultForm.choose')"
|
|
|
+ class="!w-240px"
|
|
|
+ @change="selectedFactoryChange"
|
|
|
+ >
|
|
|
<el-option
|
|
|
v-for="item in factoryList"
|
|
|
:key="item.id"
|
|
|
@@ -18,8 +25,18 @@
|
|
|
/>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
- <el-form-item :label="t('workOrderMaterial.storageLocation')" prop="storageLocationId" style="margin-left: 28px">
|
|
|
- <el-select v-model="queryParams.storageLocationId" clearable filterable :placeholder="t('faultForm.choose')" class="!w-240px">
|
|
|
+ <el-form-item
|
|
|
+ :label="t('workOrderMaterial.storageLocation')"
|
|
|
+ prop="storageLocationId"
|
|
|
+ style="margin-left: 28px"
|
|
|
+ >
|
|
|
+ <el-select
|
|
|
+ v-model="queryParams.storageLocationId"
|
|
|
+ clearable
|
|
|
+ filterable
|
|
|
+ :placeholder="t('faultForm.choose')"
|
|
|
+ class="!w-240px"
|
|
|
+ >
|
|
|
<el-option
|
|
|
v-for="item in storageLocationList"
|
|
|
:key="item.id"
|
|
|
@@ -73,15 +90,14 @@
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
|
<el-form-item>
|
|
|
- <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> {{ t('operationFill.search') }}</el-button>
|
|
|
- <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> {{ t('operationFill.reset') }}</el-button>
|
|
|
- <el-button
|
|
|
- type="success"
|
|
|
- plain
|
|
|
- @click="handleExport"
|
|
|
- :loading="exportLoading"
|
|
|
- v-hasPermi="['pms:iot-sap-stock:export']"
|
|
|
+ <el-button @click="handleQuery"
|
|
|
+ ><Icon icon="ep:search" class="mr-5px" /> {{ t('operationFill.search') }}</el-button
|
|
|
+ >
|
|
|
+ <el-button @click="resetQuery"
|
|
|
+ ><Icon icon="ep:refresh" class="mr-5px" /> {{ t('operationFill.reset') }}</el-button
|
|
|
>
|
|
|
+ <!-- v-hasPermi="['pms:iot-sap-stock:export']" -->
|
|
|
+ <el-button type="success" plain @click="handleExport" :loading="exportLoading">
|
|
|
<Icon icon="ep:download" class="mr-5px" /> 导出
|
|
|
</el-button>
|
|
|
</el-form-item>
|
|
|
@@ -98,7 +114,15 @@
|
|
|
</div>
|
|
|
<div class="stat-item">
|
|
|
<span class="stat-label">{{ t('stock.totalAmount') }}:</span>
|
|
|
- <span class="stat-value">¥ {{ totalAmount.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}</span>
|
|
|
+ <span class="stat-value"
|
|
|
+ >¥
|
|
|
+ {{
|
|
|
+ totalAmount.toLocaleString(undefined, {
|
|
|
+ minimumFractionDigits: 2,
|
|
|
+ maximumFractionDigits: 2
|
|
|
+ })
|
|
|
+ }}</span
|
|
|
+ >
|
|
|
</div>
|
|
|
</div>
|
|
|
</el-card>
|
|
|
@@ -106,18 +130,62 @@
|
|
|
|
|
|
<!-- 列表 -->
|
|
|
<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.storageLocation')" align="center"
|
|
|
- prop="projectDepartment" :width="columnWidths.projectDepartment"/>
|
|
|
- <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" :width="columnWidths.quantity"/>
|
|
|
- <el-table-column :label="t('workOrderMaterial.unitPrice')" align="center" prop="unitPrice" :width="columnWidths.unitPrice"/>
|
|
|
- <el-table-column :label="t('workOrderMaterial.unit')" align="center" prop="unit" :width="columnWidths.unit"/>
|
|
|
- <el-table-column :label="t('route.safetyStock')" align="center" prop="safetyStock" :width="columnWidths.safetyStock"/>
|
|
|
+ <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.storageLocation')"
|
|
|
+ align="center"
|
|
|
+ prop="projectDepartment"
|
|
|
+ :width="columnWidths.projectDepartment"
|
|
|
+ />
|
|
|
+ <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"
|
|
|
+ :width="columnWidths.quantity"
|
|
|
+ />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('workOrderMaterial.unitPrice')"
|
|
|
+ align="center"
|
|
|
+ prop="unitPrice"
|
|
|
+ :width="columnWidths.unitPrice"
|
|
|
+ />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('workOrderMaterial.unit')"
|
|
|
+ align="center"
|
|
|
+ prop="unit"
|
|
|
+ :width="columnWidths.unit"
|
|
|
+ />
|
|
|
+ <el-table-column
|
|
|
+ :label="t('route.safetyStock')"
|
|
|
+ align="center"
|
|
|
+ prop="safetyStock"
|
|
|
+ :width="columnWidths.safetyStock"
|
|
|
+ />
|
|
|
<el-table-column
|
|
|
:label="t('chooseMaintain.createTime')"
|
|
|
align="center"
|
|
|
@@ -144,7 +212,7 @@ import { dateFormatter } from '@/utils/formatTime'
|
|
|
import download from '@/utils/download'
|
|
|
import { IotSapStockApi, IotSapStockVO } from '@/api/pms/iotsapstock'
|
|
|
import IotSapStockForm from './IotSapStockForm.vue'
|
|
|
-import * as SapOrgApi from "@/api/system/saporg";
|
|
|
+import * as SapOrgApi from '@/api/system/saporg'
|
|
|
|
|
|
/** PMS SAP 库存(通用库存/项目部库存) 列表 */
|
|
|
defineOptions({ name: 'IotSapStock' })
|
|
|
@@ -152,11 +220,11 @@ defineOptions({ name: 'IotSapStock' })
|
|
|
const message = useMessage() // 消息弹窗
|
|
|
const { t } = useI18n() // 国际化
|
|
|
|
|
|
-const factoryList = ref([] as SapOrgApi.SapOrgVO[]) // 工厂列表
|
|
|
+const factoryList = ref([] as SapOrgApi.SapOrgVO[]) // 工厂列表
|
|
|
const storageLocationList = ref([] as SapOrgApi.SapOrgVO[]) // 库存地点列表
|
|
|
// 新增统计变量
|
|
|
-const totalQuantity = ref(0) // 总数量
|
|
|
-const totalAmount = ref(0) // 总金额
|
|
|
+const totalQuantity = ref(0) // 总数量
|
|
|
+const totalAmount = ref(0) // 总金额
|
|
|
|
|
|
const loading = ref(true) // 列表的加载中
|
|
|
const list = ref<IotSapStockVO[]>([]) // 列表的数据
|
|
|
@@ -187,7 +255,7 @@ const queryParams = reactive({
|
|
|
status: undefined,
|
|
|
remark: undefined,
|
|
|
configFlag: 'A',
|
|
|
- createTime: [],
|
|
|
+ createTime: []
|
|
|
})
|
|
|
const queryFormRef = ref() // 搜索的表单
|
|
|
const exportLoading = ref(false) // 导出的加载中
|
|
|
@@ -211,120 +279,142 @@ const columnWidths = ref({
|
|
|
|
|
|
/** 获取滚动条宽度 */
|
|
|
const getScrollbarWidth = () => {
|
|
|
- const outer = document.createElement('div');
|
|
|
- outer.style.visibility = 'hidden';
|
|
|
- outer.style.overflow = 'scroll';
|
|
|
- document.body.appendChild(outer);
|
|
|
+ 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 inner = document.createElement('div')
|
|
|
+ outer.appendChild(inner)
|
|
|
|
|
|
- const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
|
|
|
- outer.parentNode?.removeChild(outer);
|
|
|
+ const scrollbarWidth = outer.offsetWidth - inner.offsetWidth
|
|
|
+ outer.parentNode?.removeChild(outer)
|
|
|
|
|
|
- return scrollbarWidth;
|
|
|
-};
|
|
|
+ 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 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(); // 动态获取滚动条宽度
|
|
|
+ const MIN_WIDTH = 80 // 最小列宽
|
|
|
+ const PADDING = 25 // 列内边距
|
|
|
+ const FLEXIBLE_COLUMN = 'materialName' // 可伸缩列
|
|
|
+ const scrollbarWidth = getScrollbarWidth() // 动态获取滚动条宽度
|
|
|
|
|
|
- if (!tableContainerRef.value?.$el || list.value.length === 0) return;
|
|
|
+ if (!tableContainerRef.value?.$el || list.value.length === 0) return
|
|
|
|
|
|
- const containerWidth = tableContainerRef.value.$el.clientWidth;
|
|
|
+ const containerWidth = tableContainerRef.value.$el.clientWidth
|
|
|
|
|
|
// 需要自适应的列配置
|
|
|
const autoColumns = [
|
|
|
{ key: 'factory', label: t('workOrderMaterial.factory'), getValue: (row) => row.factory },
|
|
|
- { key: 'projectDepartment', label: t('workOrderMaterial.storageLocation'), getValue: (row) => row.projectDepartment },
|
|
|
- { key: 'materialCode', label: t('chooseMaintain.materialCode'), getValue: (row) => row.materialCode },
|
|
|
- { key: 'materialName', label: t('chooseMaintain.materialName'), getValue: (row) => row.materialName },
|
|
|
+ {
|
|
|
+ key: 'projectDepartment',
|
|
|
+ label: t('workOrderMaterial.storageLocation'),
|
|
|
+ getValue: (row) => row.projectDepartment
|
|
|
+ },
|
|
|
+ {
|
|
|
+ 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) => String(row.quantity) },
|
|
|
- { key: 'unitPrice', label: t('workOrderMaterial.unitPrice'), getValue: (row) => String(row.unitPrice) },
|
|
|
+ {
|
|
|
+ key: 'unitPrice',
|
|
|
+ label: t('workOrderMaterial.unitPrice'),
|
|
|
+ getValue: (row) => String(row.unitPrice)
|
|
|
+ },
|
|
|
{ key: 'unit', label: t('workOrderMaterial.unit'), getValue: (row) => row.unit },
|
|
|
- { key: 'safetyStock', label: t('route.safetyStock'), getValue: (row) => String(row.safetyStock) },
|
|
|
+ {
|
|
|
+ key: 'safetyStock',
|
|
|
+ label: t('route.safetyStock'),
|
|
|
+ getValue: (row) => String(row.safetyStock)
|
|
|
+ },
|
|
|
{
|
|
|
key: 'createTime',
|
|
|
label: t('chooseMaintain.createTime'),
|
|
|
getValue: (row) => dateFormatter(null, null, row.createTime)
|
|
|
}
|
|
|
- ];
|
|
|
+ ]
|
|
|
|
|
|
- const newWidths: Record<string, string> = {};
|
|
|
- let totalFixedWidth = 0; // 所有固定列的总宽度
|
|
|
+ const newWidths: Record<string, string> = {}
|
|
|
+ let totalFixedWidth = 0 // 所有固定列的总宽度
|
|
|
|
|
|
// 计算除可伸缩列外的所有列宽度
|
|
|
- autoColumns.forEach(col => {
|
|
|
- if (col.key === FLEXIBLE_COLUMN) return;
|
|
|
+ autoColumns.forEach((col) => {
|
|
|
+ if (col.key === FLEXIBLE_COLUMN) return
|
|
|
|
|
|
- const headerText = col.label;
|
|
|
- const headerWidth = getTextWidth(headerText) * 1.3; // 表头宽度(加粗效果增加30%)
|
|
|
+ const headerText = col.label
|
|
|
+ const headerWidth = getTextWidth(headerText) * 1.3 // 表头宽度(加粗效果增加30%)
|
|
|
|
|
|
// 计算内容最大宽度
|
|
|
- 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;
|
|
|
- });
|
|
|
+ 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;
|
|
|
- });
|
|
|
+ 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);
|
|
|
+ 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 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;
|
|
|
+ const baseWidth = Math.max(headerWidth, contentMaxWidth, MIN_WIDTH) + PADDING
|
|
|
|
|
|
// 剩余空间 = 容器宽度 - 其他列总宽度 - 垂直滚动条宽度
|
|
|
- const remainingWidth = containerWidth - totalFixedWidth - scrollbarWidth;
|
|
|
+ const remainingWidth = containerWidth - totalFixedWidth - scrollbarWidth
|
|
|
|
|
|
// 可伸缩列的宽度取剩余空间和基础宽度的最大值
|
|
|
- const flexibleWidth = Math.max(remainingWidth, baseWidth);
|
|
|
- newWidths[FLEXIBLE_COLUMN] = `${flexibleWidth}px`;
|
|
|
+ const flexibleWidth = Math.max(remainingWidth, baseWidth)
|
|
|
+ newWidths[FLEXIBLE_COLUMN] = `${flexibleWidth}px`
|
|
|
}
|
|
|
|
|
|
// 更新列宽度
|
|
|
- columnWidths.value = newWidths;
|
|
|
+ columnWidths.value = newWidths
|
|
|
|
|
|
// 重新布局表格
|
|
|
nextTick(() => {
|
|
|
- tableRef.value?.doLayout();
|
|
|
- });
|
|
|
-};
|
|
|
+ tableRef.value?.doLayout()
|
|
|
+ })
|
|
|
+}
|
|
|
|
|
|
/** 查询列表 */
|
|
|
const getList = async () => {
|
|
|
@@ -381,9 +471,8 @@ const selectedFactoryReqVO = ref({
|
|
|
|
|
|
/** 已经选择了 SAP工厂 */
|
|
|
const selectedFactoryChange = async (selectedId: number | undefined) => {
|
|
|
-
|
|
|
// 获取选中的factoryCode数组
|
|
|
- const selectedFactory = factoryList.value.find(item => item.id === selectedId)
|
|
|
+ const selectedFactory = factoryList.value.find((item) => item.id === selectedId)
|
|
|
const selectedFactoryCodes = selectedFactory ? [selectedFactory.factoryCode] : []
|
|
|
|
|
|
// 获得已经选择的 SAP 工厂 数组
|
|
|
@@ -408,7 +497,7 @@ const resultOptions = computed(() => [
|
|
|
{
|
|
|
label: '否',
|
|
|
value: 'N' // 空值会触发 clearable 效果
|
|
|
- },
|
|
|
+ }
|
|
|
])
|
|
|
|
|
|
/** 删除按钮操作 */
|
|
|
@@ -427,12 +516,9 @@ const handleDelete = async (id: number) => {
|
|
|
/** 导出按钮操作 */
|
|
|
const handleExport = async () => {
|
|
|
try {
|
|
|
- // 导出的二次确认
|
|
|
- await message.exportConfirm()
|
|
|
- // 发起导出
|
|
|
exportLoading.value = true
|
|
|
const data = await IotSapStockApi.exportIotSapStock(queryParams)
|
|
|
- download.excel(data, 'PMS SAP 库存(通用库存/项目部库存).xls')
|
|
|
+ download.excel(data, 'SPA库存.xls')
|
|
|
} catch {
|
|
|
} finally {
|
|
|
exportLoading.value = false
|
|
|
@@ -452,10 +538,13 @@ onUnmounted(() => {
|
|
|
})
|
|
|
|
|
|
// 监听列表数据变化,重新计算列宽
|
|
|
-watch(list, () => {
|
|
|
- nextTick(calculateColumnWidths)
|
|
|
-}, { deep: true })
|
|
|
-
|
|
|
+watch(
|
|
|
+ list,
|
|
|
+ () => {
|
|
|
+ nextTick(calculateColumnWidths)
|
|
|
+ },
|
|
|
+ { deep: true }
|
|
|
+)
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
@@ -485,7 +574,7 @@ watch(list, () => {
|
|
|
.stat-value {
|
|
|
font-size: 18px;
|
|
|
font-weight: bold;
|
|
|
- color: #409EFF;
|
|
|
+ color: #409eff;
|
|
|
}
|
|
|
|
|
|
/* 表格容器样式 - 确保可以水平滚动 */
|
|
|
@@ -526,5 +615,4 @@ watch(list, () => {
|
|
|
overflow: visible;
|
|
|
text-overflow: unset;
|
|
|
}
|
|
|
-
|
|
|
</style>
|