gaoluyang
3 天以前 f2770f03e7251b32eb576113c522bfbe96e5e385
src/pages/productionManagement/workOrder/index.vue
@@ -1,27 +1,34 @@
<template>
  <view class="work-order">
    <!-- 通用页面头部 -->
    <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.workOrderNo"
            @confirm="handleQuery"
            clearable
          />
          <up-input class="search-text"
                    v-model="data.searchForm.workOrderNo"
                    placeholder="工单编号"
                    @confirm="handleQuery"
                    clearable />
        </view>
        <view class="search-input">
          <up-input class="search-text"
                    v-model="data.searchForm.npsNo"
                    placeholder="生产订单号"
                    @confirm="handleQuery"
                    clearable />
        </view>
        <view class="filter-button" @click="handleQuery">
          <up-icon name="search" size="24" color="#999"></up-icon>
        </view>
      </view>
      <view class="switch-row">
        <text class="switch-label">仅看我的</text>
        <up-switch v-model="filterMine" @change="handleQuery" size="18" />
      </view>
    </view>
    <!-- 工单列表 -->
    <scroll-view scroll-y class="ledger-list" v-if="tableData.length > 0" @scrolltolower="loadMore">
      <view v-for="(item, index) in tableData" :key="item.id || index" class="ledger-item">
@@ -36,10 +43,14 @@
            <text class="item-tag tag-type">{{ item.workOrderType }}</text>
          </view>
        </view>
        <up-divider></up-divider>
        <view class="item-details">
          <view class="detail-row">
            <text class="detail-label">生产订单号</text>
            <text class="detail-value">{{ item.npsNo || '-' }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">产品名称</text>
            <text class="detail-value">{{ item.productName }}</text>
@@ -50,24 +61,24 @@
          </view>
          <view class="detail-row">
            <text class="detail-label">工序名称</text>
            <text class="detail-value">{{ item.processName }}</text>
            <text class="detail-value">{{ item.operationName }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">需求/完成数量</text>
            <text class="detail-value">{{ item.planQuantity }} / {{ item.completeQuantity }} {{ item.unit }}</text>
          </view>
          <view class="progress-section">
            <text class="detail-label">完成进度</text>
            <view class="progress-bar">
              <up-line-progress
                :percentage="toProgressPercentage(item.completionStatus)"
              <up-line-progress
                :percentage="toProgressPercentage(item.completionStatus)"
                activeColor="#2979ff"
                :showText="true"
              ></up-line-progress>
            </view>
          </view>
          <view class="detail-row">
            <text class="detail-label">计划开始</text>
            <text class="detail-value">{{ item.planStartTime }}</text>
@@ -76,51 +87,52 @@
            <text class="detail-label">计划结束</text>
            <text class="detail-value">{{ item.planEndTime }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">实际开始</text>
            <text class="detail-value">{{ item.actualStartTime || '-' }}</text>
          </view>
          <view class="detail-row">
            <text class="detail-label">实际结束</text>
            <text class="detail-value">{{ item.actualEndTime || '-' }}</text>
          </view>
        </view>
        <view class="item-actions">
          <up-button v-if="showStartReport(item)"
                     class="action-btn"
                     size="small"
                     type="primary"
                     @click="handleStartWork(item)">开始报工</up-button>
          <up-button v-if="showEndReport(item)"
                     class="action-btn"
                     size="small"
                     type="success"
                     @click="goReport(item)">结束报工</up-button>
        </view>
      </view>
      <up-loadmore :status="loadStatus" />
    </scroll-view>
    <view v-else-if="!loading" class="no-data">
      <up-empty mode="data" text="暂无工单数据"></up-empty>
    </view>
    <!-- 流转卡弹窗 -->
    <up-popup :show="transferCardVisible" mode="center" @close="transferCardVisible = false" round="10">
      <view class="qr-popup">
        <text class="qr-title">工单流转卡二维码</text>
        <view class="qr-box">
          <geek-qrcode
            v-if="transferCardRowData"
            :val="String(transferCardRowData.id)"
            :size="200"
          />
        </view>
        <text class="qr-info" v-if="transferCardRowData">{{ transferCardRowData.workOrderNo }}</text>
        <up-button text="关闭" @click="transferCardVisible = false" style="margin-top: 20px;"></up-button>
      </view>
    </up-popup>
    <!-- 附件组件 -->
    <FilesDia ref="workOrderFilesRef" />
  </view>
</template>
<script setup>
import { ref, reactive, toRefs, getCurrentInstance } from "vue";
import { ref, reactive } from "vue";
import { onShow } from '@dcloudio/uni-app';
import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
import { productWorkOrderPage, startWork } from "@/api/productionManagement/workOrder.js";
import PageHeader from "@/components/PageHeader.vue";
import FilesDia from "./components/filesDia.vue";
import useUserStore from "@/store/modules/user";
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const loading = ref(false);
const tableData = ref([]);
const loadStatus = ref('loadmore');
const transferCardVisible = ref(false);
const transferCardRowData = ref(null);
const workOrderFilesRef = ref(null);
const filterMine = ref(false);
const page = reactive({
  current: 1,
@@ -131,9 +143,20 @@
const data = reactive({
  searchForm: {
    workOrderNo: "",
    npsNo: "",
  },
});
const { searchForm } = toRefs(data);
const isCompleted = row => {
  const status = Number(row?.completionStatus);
  return Number.isFinite(status) && status >= 100;
};
const canOperate = row => !row.endOrder && !isCompleted(row);
const showStartReport = row => canOperate(row) && !row.actualStartTime;
const showEndReport = row => canOperate(row) && !!row.actualStartTime;
const goBack = () => {
  uni.navigateBack();
@@ -148,15 +171,18 @@
const getList = () => {
  if (loading.value) return;
  loading.value = true;
  const params = { ...searchForm.value, ...page };
  const params = { ...data.searchForm, ...page };
  if (filterMine.value) {
    params.filterMine = true;
  }
  productWorkOrderPage(params).then((res) => {
    loading.value = false;
    const records = res.data.records || [];
    tableData.value = page.current === 1 ? records : [...tableData.value, ...records];
    page.total = res.data.total;
    if (tableData.value.length >= page.total) {
      loadStatus.value = 'nomore';
    } else {
@@ -182,13 +208,34 @@
  return Math.round(n);
};
const showTransferCard = (row) => {
  transferCardRowData.value = row;
  transferCardVisible.value = true;
const handleStartWork = (row) => {
  uni.showModal({
    title: "提示",
    content: "确认开始报工?",
    success: res => {
      if (res.confirm) {
        startWork({
          productionOperationTaskId: row.id,
          userId: userStore.id,
        })
          .then(() => {
            uni.showToast({ title: "开始报工成功" });
            handleQuery();
          })
          .catch(() => {
            uni.showToast({ title: "开始报工失败", icon: "error" });
          });
      }
    },
  });
};
const openWorkOrderFiles = (row) => {
  workOrderFilesRef.value?.openDialog(row);
const goReport = (row) => {
  uni.navigateTo({
    url: `/pages/productionManagement/productionReport/index?orderRow=${encodeURIComponent(
      JSON.stringify(row)
    )}`,
  });
};
onShow(() => {
@@ -228,37 +275,10 @@
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid #f5f5f5;
  :deep(.up-button) {
  .action-btn {
    margin: 0;
    width: auto;
  }
}
.qr-popup {
  padding: 30px;
  background-color: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  .qr-title {
    font-size: 18px;
    font-weight: bold;
    margin-bottom: 20px;
  }
  .qr-box {
    padding: 20px;
    background-color: #fff;
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    margin-bottom: 15px;
  }
  .qr-info {
    font-size: 14px;
    color: #666;
  }
}