zhangwencui
2026-05-06 5b3d68b45ced3d09078e77658641b3f6c7537338
报工台账模块开发
已添加2个文件
已修改2个文件
457 ■■■■■ 文件已修改
src/api/productionManagement/productionProductMain.js 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages.json 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/productionManagement/productionReporting/ledger.vue 412 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pages/works.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/productionManagement/productionProductMain.js
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
// ç”Ÿäº§æŠ¥å·¥é¡µé¢æŽ¥å£
import request from "@/utils/request";
// åˆ†é¡µæŸ¥è¯¢ç”Ÿäº§æŠ¥å·¥ä¸»è¡¨
export function productionProductMainListPage(query) {
    return request({
        url: "/productionProductMain/listPage",
        method: "get",
        params: query,
    });
}
// åˆ é™¤æŠ¥å·¥
export function productionReportDelete(query) {
    return request({
        url: "/productionProductMain/delete",
        method: "get",
        params: query,
    });
}
// æŸ¥è¯¢æŠ•入列表
export function productionProductInputListPage(query) {
    return request({
        url: "/productionProductInput/listPage",
        method: "get",
        params: query,
    });
}
src/pages.json
@@ -824,6 +824,13 @@
      }
    },
    {
      "path": "pages/productionManagement/productionReporting/ledger",
      "style": {
        "navigationBarTitleText": "报工台账",
        "navigationStyle": "custom"
      }
    },
    {
      "path": "pages/productionManagement/workOrder/index",
      "style": {
        "navigationBarTitleText": "生产工单",
src/pages/productionManagement/productionReporting/ledger.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,412 @@
<template>
  <view class="reporting-ledger">
    <PageHeader title="报工台账"
                @back="goBack" />
    <!-- æœç´¢åŒºåŸŸ - å‚考采购台账样式 -->
    <view class="search-section">
      <view class="search-bar">
        <view class="search-input">
          <up-input class="search-text"
                    placeholder="请输入工单号搜索"
                    v-model="searchForm.keyword"
                    @change="handleQuery"
                    clearable />
        </view>
        <view class="filter-button"
              @click="handleQuery">
          <up-icon name="search"
                   size="24"
                   color="#999"></up-icon>
        </view>
      </view>
    </view>
    <!-- åˆ—表区域 -->
    <scroll-view scroll-y
                 class="list-container"
                 v-if="tableData.length > 0"
                 @scrolltolower="loadMore">
      <view class="ledger-list">
        <view v-for="(item, index) in tableData"
              :key="item.id || index">
          <view class="ledger-item">
            <view class="item-header">
              <view class="item-left">
                <view class="document-icon">
                  <up-icon name="file-text"
                           size="16"
                           color="#ffffff"></up-icon>
                </view>
                <text class="item-id">{{ item.productNo || '-' }}</text>
              </view>
              <view class="item-tag">
                <text class="create-time">{{ formatDate(item.createTime) }}</text>
              </view>
            </view>
            <up-divider></up-divider>
            <view class="item-details">
              <view class="detail-row">
                <text class="detail-label">报工人员</text>
                <text class="detail-value highlight">{{ item.nickName || '-' }}</text>
              </view>
              <view class="detail-row">
                <text class="detail-label">所属工序</text>
                <view class="detail-value">
                  <up-tag :text="item.process || '-'"
                          type="primary"
                          size="mini"
                          plain />
                </view>
              </view>
              <view class="detail-row">
                <text class="detail-label">工单编号</text>
                <text class="detail-value">{{ item.workOrderNo || '-' }}</text>
              </view>
              <view class="detail-row">
                <text class="detail-label">产品名称</text>
                <text class="detail-value font-bold">{{ item.productName || '-' }}</text>
              </view>
              <view class="detail-row">
                <text class="detail-label">规格型号</text>
                <text class="detail-value">{{ item.productModelName || '-' }}</text>
              </view>
              <view class="quantity-section">
                <view class="qty-item">
                  <text class="qty-label">产出数量</text>
                  <text class="qty-value success">{{ item.quantity || 0 }} {{ item.unit || '' }}</text>
                </view>
                <view class="qty-item">
                  <text class="qty-label">报废数量</text>
                  <text class="qty-value error">{{ item.scrapQty || 0 }}</text>
                </view>
              </view>
              <view class="item-footer">
                <view class="action-buttons">
                  <up-button type="primary"
                             size="small"
                             plain
                             text="查看投入"
                             @click="handleShowInput(item)"></up-button>
                  <up-button type="info"
                             size="small"
                             plain
                             text="参数详情"
                             @click="handleShowParams(item)"></up-button>
                  <up-button type="error"
                             size="small"
                             plain
                             text="删除"
                             @click="handleDelete(item)"></up-button>
                </view>
              </view>
            </view>
          </view>
        </view>
      </view>
      <up-loadmore :status="loadStatus"
                   v-if="tableData.length >= page.size" />
    </scroll-view>
    <view v-else
          class="empty-state">
      <up-empty mode="data"
                text="暂无报工台账数据"></up-empty>
    </view>
    <!-- æŠ•入详情弹窗 -->
    <up-modal :show="inputVisible"
              title="投入详情"
              @confirm="inputVisible = false">
      <view class="modal-content scroll-view">
        <view v-if="inputList.length > 0">
          <view v-for="(input, idx) in inputList"
                :key="idx"
                class="detail-item">
            <view class="detail-row">
              <text class="detail-label">投入产品</text>
              <text class="detail-value font-bold">{{ input.productName }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">规格型号</text>
              <text class="detail-value">{{ input.model }}</text>
            </view>
            <view class="detail-row">
              <text class="detail-label">投入数量</text>
              <text class="detail-value highlight">{{ input.quantity }} {{ input.unit }}</text>
            </view>
            <up-divider></up-divider>
          </view>
        </view>
        <up-empty v-else
                  mode="data"
                  text="暂无投入数据" />
      </view>
    </up-modal>
    <!-- å‚数详情弹窗 -->
    <up-modal :show="paramsVisible"
              title="参数详情"
              @confirm="paramsVisible = false">
      <view class="modal-content">
        <view v-if="currentParams.length > 0">
          <view v-for="(param, idx) in currentParams"
                :key="idx"
                class="detail-row">
            <text class="detail-label">{{ param.paramName }}</text>
            <text class="detail-value">{{ param.inputValue }} {{ param.unit && param.unit !== '/' ? '(' + param.unit + ')' : '' }}</text>
          </view>
        </view>
        <up-empty v-else
                  mode="data"
                  text="暂无参数数据" />
      </view>
    </up-modal>
  </view>
</template>
<script setup>
  import { ref, reactive, onMounted } from "vue";
  import dayjs from "dayjs";
  import {
    productionProductMainListPage,
    productionReportDelete,
    productionProductInputListPage,
  } from "@/api/productionManagement/productionProductMain.js";
  import PageHeader from "@/components/PageHeader.vue";
  import modal from "@/plugins/modal";
  const tableData = ref([]);
  const loading = ref(false);
  const loadStatus = ref("loadmore");
  const page = reactive({
    current: 1,
    size: 10,
    total: 0,
  });
  const searchForm = reactive({
    keyword: "",
  });
  // æŠ•入详情相关
  const inputVisible = ref(false);
  const inputList = ref([]);
  // å‚数详情相关
  const paramsVisible = ref(false);
  const currentParams = ref([]);
  const goBack = () => {
    uni.navigateBack();
  };
  const formatDate = date => {
    return date ? dayjs(date).format("YYYY-MM-DD HH:mm") : "-";
  };
  const handleQuery = () => {
    page.current = 1;
    tableData.value = [];
    getList();
  };
  const loadMore = () => {
    if (loadStatus.value === "nomore" || loading.value) return;
    page.current++;
    getList();
  };
  const getList = () => {
    loading.value = true;
    loadStatus.value = "loading";
    const params = {
      current: page.current,
      size: page.size,
      workOrderNo: searchForm.keyword,
    };
    productionProductMainListPage(params)
      .then(res => {
        loading.value = false;
        const records = res.data.records || [];
        if (page.current === 1) {
          tableData.value = records;
        } else {
          tableData.value = [...tableData.value, ...records];
        }
        if (records.length < page.size) {
          loadStatus.value = "nomore";
        } else {
          loadStatus.value = "loadmore";
        }
        page.total = res.data.total || 0;
      })
      .catch(() => {
        loading.value = false;
        loadStatus.value = "loadmore";
        modal.msgError("加载失败");
      });
  };
  const handleShowInput = item => {
    modal.loading("加载中...");
    productionProductInputListPage({
      productMainId: item.id,
      current: 1,
      size: 100,
    })
      .then(res => {
        modal.closeLoading();
        inputList.value = res.data.records || [];
        inputVisible.value = true;
      })
      .catch(() => {
        modal.closeLoading();
        modal.msgError("加载投入数据失败");
      });
  };
  const handleShowParams = item => {
    currentParams.value = item.productionOperationParamList || [];
    paramsVisible.value = true;
  };
  const handleDelete = item => {
    uni.showModal({
      title: "提示",
      content: "确定要删除该报工记录吗?",
      success: res => {
        if (res.confirm) {
          productionReportDelete({ id: item.id }).then(res => {
            if (res.code === 200) {
              modal.msgSuccess("删除成功");
              handleQuery();
            } else {
              modal.msgError(res.msg || "删除失败");
            }
          });
        }
      },
    });
  };
  onMounted(() => {
    getList();
  });
</script>
<style scoped lang="scss">
  @import "@/styles/procurement-common.scss";
  .reporting-ledger {
    min-height: 100vh;
    background-color: #f8f9fa;
    display: flex;
    flex-direction: column;
  }
  .list-container {
    flex: 1;
    height: 0;
  }
  .ledger-item {
    .item-header {
      .item-tag {
        .create-time {
          font-size: 24rpx;
          color: #999;
        }
      }
    }
    .item-details {
      .quantity-section {
        display: flex;
        background-color: #f9f9f9;
        border-radius: 8rpx;
        padding: 20rpx;
        margin: 20rpx 0;
        .qty-item {
          flex: 1;
          display: flex;
          flex-direction: column;
          align-items: center;
          &:first-child {
            border-right: 1rpx solid #eee;
          }
          .qty-label {
            font-size: 24rpx;
            color: #999;
            margin-bottom: 8rpx;
          }
          .qty-value {
            font-size: 32rpx;
            font-weight: bold;
            &.success {
              color: #52c41a;
            }
            &.error {
              color: #f56c6c;
            }
          }
        }
      }
      .item-footer {
        padding-top: 20rpx;
        border-top: 1rpx solid #f0f0f0;
        .action-buttons {
          display: flex;
          justify-content: flex-end;
          gap: 20rpx;
        }
      }
    }
  }
  .modal-content {
    width: 100%;
    padding: 20rpx 0;
    max-height: 60vh;
    overflow-y: auto;
    .detail-item {
      padding-bottom: 20rpx;
    }
    .detail-row {
      display: flex;
      justify-content: space-between;
      margin-bottom: 16rpx;
      .detail-label {
        font-size: 26rpx;
        color: #999;
      }
      .detail-value {
        font-size: 26rpx;
        color: #333;
        &.font-bold {
          font-weight: bold;
        }
        &.highlight {
          color: #3c9cff;
        }
      }
    }
  }
  .empty-state {
    padding-top: 200rpx;
  }
</style>
src/pages/works.vue
@@ -589,6 +589,10 @@
      icon: "/static/images/icon/shengchanbaogong.svg",
      label: "生产报工",
    },
    {
      icon: "/static/images/icon/xiaoshoutaizhang.svg",
      label: "报工台账",
    },
    // {
    //   icon: "/static/images/icon/shengchanbaogong.svg",
    //   label: "生产工单",
@@ -860,6 +864,11 @@
      case "生产报工":
        getcode();
        break;
      case "报工台账":
        uni.navigateTo({
          url: "/pages/productionManagement/productionReporting/ledger",
        });
        break;
      case "生产核算":
        uni.navigateTo({
          url: "/pages/productionManagement/productionAccounting/index",