buhuazhen
11 小时以前 9c3cca091f8e69a6f96a356a7ad093d68240ebe3
feat(生产核算): 添加工时明细查看功能

在左侧汇总台账表格中新增“工时(分钟)”列,显示总工时数。当工时大于0时,点击可弹出对话框查看按机台细分的工时明细列表。同时调整代码格式以保持一致性。
已修改1个文件
392 ■■■■■ 文件已修改
src/views/productionManagement/productionCosting/index.vue 392 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/productionManagement/productionCosting/index.vue
@@ -29,145 +29,196 @@
          </el-form>
                </div>
                <PIMTable
                    rowKey="id"
                    :column="leftTableColumn"
                    :tableData="leftTableData"
                    :tableLoading="tableLoading"
          :page="page"
          @row-click="handleLeftRowClick"
          @pagination="pagination"
        ></PIMTable>
            rowKey="id"
            :column="leftTableColumn"
            :tableData="leftTableData"
            :tableLoading="tableLoading"
            :page="page"
            @row-click="handleLeftRowClick"
            @pagination="pagination"
        >
          <template #workDuration="{ row }">
            <el-button v-if="Number(row.totalWorkMinutes) > 0"
                       type="primary"
                       text
                       @click.stop="openWorkDurationDialog(row)">
              {{ row.totalWorkMinutes }}
            </el-button>
            <span v-else>-</span>
          </template>
        </PIMTable>
                </div>
            </el-col>
            <!-- 右侧明细 -->
      <!-- 右侧明细 -->
            <el-col :xs="24" :sm="24" :md="24" :lg="16" :xl="16" class="right-col">
                <div class="right-panel">
                    <el-form inline>
                        <el-form-item>
                            <el-button type="primary" @click="handleOut">导出</el-button>
                        </el-form-item>
                    </el-form>
                    <PIMTable
                        rowKey="id"
                        :column="tableColumn"
                        :tableData="tableData"
                        :page="page1"
                        :tableLoading="tableLoading1"
                        style="margin-right: 20px;"
                        @pagination="pagination1"
                    ></PIMTable>
              rowKey="id"
              :column="tableColumn"
              :tableData="tableData"
              :page="page1"
              :tableLoading="tableLoading1"
              style="margin-right: 20px;"
              @pagination="pagination1"
          ></PIMTable>
                </div>
            </el-col>
        </el-row>
    <el-dialog v-model="workDurationDialogVisible"
               :title="`工时明细${currentSchedulingUserName ? ` - ${currentSchedulingUserName}` : ''}`"
               width="600px">
      <el-table :data="workDurationDetailList"
                border
                style="width: 100%; margin-bottom: 16px;">
        <el-table-column type="index"
                         label="序号"
                         width="80"/>
        <el-table-column prop="deviceName"
                         label="机台"
                         min-width="220"/>
        <el-table-column prop="workMinutes"
                         label="工作时间(分钟)"
                         min-width="160"/>
      </el-table>
    </el-dialog>
    </div>
</template>
<script setup>
import {onMounted, ref} from "vue";
import { ElMessageBox } from "element-plus";
import {ElMessageBox} from "element-plus";
import dayjs from "dayjs";
import {salesLedgerProductionAccountingListProductionDetails, salesLedgerProductionAccountingList} from "@/api/productionManagement/productionCosting.js";
const { proxy } = getCurrentInstance();
import {
  salesLedgerProductionAccountingListProductionDetails,
  salesLedgerProductionAccountingList
} from "@/api/productionManagement/productionCosting.js";
const {proxy} = getCurrentInstance();
const tableColumn = ref([
    {
        label: "生产日期",
        prop: "schedulingDate",
  {
    label: "生产日期",
    prop: "schedulingDate",
    minWidth: 100,
    },
    {
        label: "生产人",
        prop: "schedulingUserName",
  },
  {
    label: "生产人",
    prop: "schedulingUserName",
    minWidth: 100,
    },
    {
        label: "合同号",
        prop: "salesContractNo",
  },
  {
    label: "合同号",
    prop: "salesContractNo",
    minWidth: 100,
    },
    {
        label: "客户名称",
        prop: "customerName",
  },
  {
    label: "客户名称",
    prop: "customerName",
    minWidth: 100,
    },
    {
        label: "产品大类",
        prop: "productName",
  },
  {
    label: "产品大类",
    prop: "productName",
    minWidth: 100,
    },
    {
        label: "规格型号",
        prop: "productModelName",
  },
  {
    label: "规格型号",
    prop: "productModelName",
    minWidth: 100,
    },
    {
        label: "单位",
        prop: "unit",
  },
  {
    label: "单位",
    prop: "unit",
    minWidth: 100,
    },
    {
        label: "工序",
        prop: "process",
  },
  {
    label: "工序",
    prop: "process",
    minWidth: 100,
    },
    {
        label: "生产数量",
        prop: "quantity",
  },
  {
    label: "生产数量",
    prop: "quantity",
    minWidth: 100,
    },
    {
        label: "工时定额",
        prop: "workHours",
  },
  {
    label: "工时定额",
    prop: "workHours",
    minWidth: 100,
    },
    {
        label: "工资",
        prop: "wages",
  },
  {
    label: "工资",
    prop: "wages",
    minWidth: 100,
    },
  },
  {
    label: "机台",
    prop: "deviceName",
    minWidth: 100,
  },
  {
    label: "工时(分钟)",
    prop: "workMinutes",
    width: 110,
  },
]);
// 左侧汇总台账列(生产人、产量、工资、合格率)
const leftTableColumn = ref([
    {
        label: "生产人",
        prop: "schedulingUserName",
  {
    label: "生产人",
    prop: "schedulingUserName",
    minWidth: 100,
    },
    {
        label: "产量",
        prop: "outputNum",
  },
  {
    label: "产量",
    prop: "outputNum",
    minWidth: 100,
  },
    {
        label: "工资",
        prop: "wages",
  {
    label: "工资",
    prop: "wages",
    minWidth: 100,
    },
    {
        label: "合格率",
        prop: "outputRate",
  },
  {
    label: "合格率",
    prop: "outputRate",
    minWidth: 100,
    formatData: (val) => {
      if (val == null || val === '') return '-'
      return parseFloat(val).toFixed(2)
    },
    },
  },
  {
    label: "工时(分钟)",
    prop: "totalWorkMinutes",
    minWidth: 120,
    dataType: "slot",
    slot: "workDuration",
  },
]);
const tableData = ref([]);
const tableLoading = ref(false);
const tableLoading1 = ref(false);
const leftTableData = ref([]);
const workDurationDialogVisible = ref(false);
const workDurationDetailList = ref([]);
const currentSchedulingUserName = ref("");
// 日 / 月 切换(默认按日)
const page = reactive({
    current: 1,
    size: 100,
    total: 0,
  current: 1,
  size: 100,
  total: 0,
});
const page1 = reactive({
@@ -177,32 +228,32 @@
});
const data = reactive({
    searchForm: {
        schedulingUserName: "",
        salesContractNo: "",
  searchForm: {
    schedulingUserName: "",
    salesContractNo: "",
    dateType: "day",
    dateRange: dayjs().format("YYYY-MM-DD"),
        entryDate: dayjs().format("YYYY-MM-DD"),
        entryDateStart: undefined,
        entryDateEnd: undefined,
    },
    entryDate: dayjs().format("YYYY-MM-DD"),
    entryDateStart: undefined,
    entryDateEnd: undefined,
  },
});
const { searchForm } = toRefs(data);
const {searchForm} = toRefs(data);
const pagination = (obj) => {
    page.current = obj.page;
    page.size = obj.limit;
    getList();
  page.current = obj.page;
  page.size = obj.limit;
  getList();
};
const pagination1 = (obj) => {
  page1.current = obj.page;
  page1.size = obj.limit;
    getList1();
  getList1();
};
const handleDateRangeChange = (value) => {
    if (value) {
  if (value) {
    if (searchForm.value.dateType === "day") {
      searchForm.value.entryDate = value;
    } else {
@@ -210,35 +261,46 @@
      searchForm.value.entryDateEnd = dayjs(value[1]).format("YYYY-MM-DD");
    }
    } else {
        searchForm.value.entryDate = undefined;
        searchForm.value.entryDateStart = undefined;
        searchForm.value.entryDateEnd = undefined;
    }
  } else {
    searchForm.value.entryDate = undefined;
    searchForm.value.entryDateStart = undefined;
    searchForm.value.entryDateEnd = undefined;
  }
  reloadData()
};
const getList = () => {
    tableLoading.value = true;
    const params = { ...searchForm.value, ...page };
  tableLoading.value = true;
  const params = {...searchForm.value, ...page};
  salesLedgerProductionAccountingList(params).then((res) => {
        const records = res.data.records || [];
    leftTableData.value = records;
        page.total = res.data.total || 0;
    }).finally(() => {
    const records = res.data.records || [];
    leftTableData.value = records.map(item => {
      const workDurationDetailListValue = buildWorkDurationDetailList(item.deviceWorkInfoPairList);
      const totalWorkMinutes = workDurationDetailListValue.reduce(
          (sum, detail) => sum + Number(detail.workMinutes || 0),
          0
      );
      return {
        ...item,
        workDurationDetailList: workDurationDetailListValue,
        totalWorkMinutes,
      };
    });
    page.total = res.data.total || 0;
  }).finally(() => {
    tableLoading.value = false;
  })
};
const getList1 = () => {
  tableLoading1.value = true;
  const params = { ...page1, ...searchForm.value };
  const params = {...page1, ...searchForm.value};
  salesLedgerProductionAccountingListProductionDetails(params).then((res) => {
    tableData.value = res.data.records || [];;
    tableData.value = res.data.records || [];
    ;
    page1.total = res.data.total || 0;
  }).finally(() => {
    tableLoading1.value = false;
@@ -247,30 +309,30 @@
// 构建左侧汇总台账(按生产人汇总产量、工资等)
const buildLeftTableData = (records) => {
    const map = {};
    records.forEach((item) => {
        const key = item.schedulingUserName || "未知";
        if (!map[key]) {
            map[key] = {
                id: key,
                schedulingUserName: key,
                finishedNum: 0,
                wages: 0,
                qualifiedRate: item.qualifiedRate ?? null,
            };
        }
        map[key].finishedNum += Number(item.finishedNum || 0);
        map[key].wages += Number(item.wages || 0);
        if (item.qualifiedRate != null) {
            map[key].qualifiedRate = item.qualifiedRate;
        }
    });
    leftTableData.value = Object.values(map);
  const map = {};
  records.forEach((item) => {
    const key = item.schedulingUserName || "未知";
    if (!map[key]) {
      map[key] = {
        id: key,
        schedulingUserName: key,
        finishedNum: 0,
        wages: 0,
        qualifiedRate: item.qualifiedRate ?? null,
      };
    }
    map[key].finishedNum += Number(item.finishedNum || 0);
    map[key].wages += Number(item.wages || 0);
    if (item.qualifiedRate != null) {
      map[key].qualifiedRate = item.qualifiedRate;
    }
  });
  leftTableData.value = Object.values(map);
};
// 左侧日/月切换
const handleDateTypeChange = (value) => {
    // 这里只作为筛选条件的一部分,直接重新查询列表
  // 这里只作为筛选条件的一部分,直接重新查询列表
  if (value === "day") {
    searchForm.value.entryDate = dayjs().format("YYYY-MM-DD");
    searchForm.value.dateRange = searchForm.value.entryDate
@@ -290,10 +352,52 @@
  tableData.value = []
}
const buildWorkDurationDetailList = (deviceWorkInfoPairList) => {
  if (!deviceWorkInfoPairList) {
    return [];
  }
  let listData = deviceWorkInfoPairList;
  if (typeof deviceWorkInfoPairList === "string") {
    try {
      listData = JSON.parse(deviceWorkInfoPairList);
    } catch {
      return [];
    }
  }
  if (!Array.isArray(listData)) {
    return [];
  }
  const details = [];
  listData.forEach(item => {
    if (!item || typeof item !== "object") {
      return;
    }
    Object.entries(item).forEach(([deviceName, workMinutes]) => {
      const numericMinutes = Number(workMinutes);
      if (deviceName) {
        details.push({
          deviceName,
          workMinutes: Number.isFinite(numericMinutes) ? numericMinutes : 0,
        });
      }
    });
  });
  return details;
};
const openWorkDurationDialog = row => {
  currentSchedulingUserName.value = row?.schedulingUserName || "";
  const details = Array.isArray(row?.workDurationDetailList)
      ? row.workDurationDetailList
      : buildWorkDurationDetailList(row?.deviceWorkInfoPairList);
  workDurationDetailList.value = details;
  workDurationDialogVisible.value = true;
};
// 点击左侧行,刷右侧明细(按生产人过滤)
const handleLeftRowClick = (row) => {
    searchForm.value.schedulingUserName = row.schedulingUserName || "";
    handleQuery();
  searchForm.value.schedulingUserName = row.schedulingUserName || "";
  handleQuery();
};
// 查询列表
@@ -306,21 +410,21 @@
// 导出
const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
        confirmButtonText: "确认",
        cancelButtonText: "取消",
        type: "warning",
    })
        .then(() => {
            proxy.download("/salesLedger/productionAccounting/export", {}, "生产核算.xlsx");
        })
        .catch(() => {
            proxy.$modal.msg("已取消");
        });
  ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
    confirmButtonText: "确认",
    cancelButtonText: "取消",
    type: "warning",
  })
      .then(() => {
        proxy.download("/salesLedger/productionAccounting/export", {}, "生产核算.xlsx");
      })
      .catch(() => {
        proxy.$modal.msg("已取消");
      });
};
onMounted(() => {
    getList();
  getList();
});
</script>