From 552ec6b7d8ccc56c379da195fc6c9c74312b1070 Mon Sep 17 00:00:00 2001
From: yyb <995253665@qq.com>
Date: 星期五, 22 五月 2026 17:57:46 +0800
Subject: [PATCH] OA部分查询条件变更

---
 src/pages/productionManagement/productionOrder/index.vue |  708 +++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 525 insertions(+), 183 deletions(-)

diff --git a/src/pages/productionManagement/productionOrder/index.vue b/src/pages/productionManagement/productionOrder/index.vue
index a7b39c9..5f31fb1 100644
--- a/src/pages/productionManagement/productionOrder/index.vue
+++ b/src/pages/productionManagement/productionOrder/index.vue
@@ -1,204 +1,546 @@
 <template>
-	<view class="production-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.customerName"
-						@change="handleQuery"
-						clearable
-					/>
-				</view>
-				<view class="filter-button" @click="handleQuery">
-					<up-icon name="search" size="24" color="#999"></up-icon>
-				</view>
-			</view>
-		</view>
-		
-		<!-- 鐢熶骇璁㈠崟鍒楄〃 -->
-		<view class="ledger-list" v-if="tableData.length > 0">
-			<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.salesContractNo }}</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.entryDate }}</text>
-						</view>
-					<!-- 	<view class="detail-row">
-							<text class="detail-label">瀹㈡埛鍚堝悓鍙�</text>
-							<text class="detail-value">{{ item.customerContractNo }}</text>
-						</view> -->
-						<view class="detail-row">
-							<text class="detail-label">瀹㈡埛鍚嶇О</text>
-							<text class="detail-value">{{ item.customerName }}</text>
-						</view>
-					<!-- 	<view class="detail-row">
-							<text class="detail-label">椤圭洰鍚嶇О</text>
-							<text class="detail-value">{{ item.projectName }}</text>
-						</view> -->
-						<view class="detail-row">
-							<text class="detail-label">浠樻鐘舵��</text>
-							<view v-if="item.status=='宸插畬鎴�'" class="detail-value">
-								<uni-tag :inverted="true" text="宸插畬鎴�" type="success" size="mini" />
-							</view>
-							<view v-else-if="item.status=='鏈畬鎴�'" class="detail-value">
-								<uni-tag :inverted="true" text="鏈畬鎴�" type="error" size="mini" />
-							</view>
-							<view v-else class="detail-value">
-								<uni-tag :inverted="true" :text="item.status" type="primary" size="mini" />
-							</view>
-						</view>
-						<view class="detail-row">
-							<text class="detail-label">浜у搧澶х被</text>
-							<text class="detail-value">{{ item.productCategory }}</text>
-						</view>
-						<view class="detail-row">
-							<text class="detail-label">瑙勬牸鍨嬪彿</text>
-							<text class="detail-value">{{ item.specificationModel }}</text>
-						</view>
-						<view class="detail-row">
-							<text class="detail-label">鏁伴噺</text>
-							<text class="detail-value">{{ item.quantity }} {{ item.unit }}</text>
-						</view>
-						<view class="detail-row">
-							<text class="detail-label">鎺掍骇鏁伴噺</text>
-							<text class="detail-value highlight">{{ item.schedulingNum }}</text>
-						</view>
-						<view class="detail-row">
-							<text class="detail-label">瀹屽伐鏁伴噺</text>
-							<text class="detail-value highlight">{{ item.successNum }}</text>
-						</view>
-					</view>
-				</view>
-			</view>
-		</view>
-		<view v-else class="no-data">
-			<text>鏆傛棤鐢熶骇璁㈠崟鏁版嵁</text>
-		</view>
-	</view>
+  <view class="production-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.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 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.npsNo }}</text>
+            </view>
+            <view class="item-right">
+              <up-tag :text="getStatusText(item.status)"
+                      :type="getStatusType(item.status)"
+                      size="mini" />
+            </view>
+          </view>
+          <up-divider></up-divider>
+          <view class="item-details">
+            <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.model || '-' }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">璁㈠崟鏁伴噺</text>
+              <text class="detail-value">{{ item.quantity || 0 }}</text>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">瀹屾垚杩涘害</text>
+              <view class="progress-box">
+                <up-line-progress :percentage="toProgressPercentage(item.completionStatus)"
+                                  :activeColor="progressColor(item.completionStatus)"
+                                  height="10"></up-line-progress>
+                <text class="progress-text">{{ item.completeQuantity || 0 }} / {{ item.quantity || 0 }}</text>
+              </view>
+            </view>
+            <!-- 宸ュ簭鐢熶骇杩涘害灞曠ず -->
+            <view class="detail-row process-row">
+              <text class="detail-label">宸ュ簭杩涘害</text>
+              <scroll-view scroll-x
+                           class="process-scroll">
+                <view class="process-container">
+                  <view v-for="(process, pIdx) in item.processRouteStatus"
+                        :key="pIdx"
+                        class="process-item">
+                    <view class="process-node">
+                      <view class="node-circle"
+                            :class="{ 'is-complete': process.percentage >= 100 }">
+                        <text class="node-percentage"
+                              :style="{ color: process.percentage >= 100 ? '#52c41a' : (process.percentage >= 70 ? '#f56c6c' : '#3c9cff') }">{{ process.percentage }}%</text>
+                      </view>
+                      <text class="node-name">{{ process.name }}</text>
+                    </view>
+                    <view v-if="pIdx < item.processRouteStatus.length - 1"
+                          class="node-line"></view>
+                  </view>
+                  <view v-if="!item.processRouteStatus || !item.processRouteStatus.length"
+                        class="no-process">-</view>
+                </view>
+              </scroll-view>
+            </view>
+            <view class="detail-row">
+              <text class="detail-label">璁″垝瀹屾垚</text>
+              <text class="detail-value">{{ formatDate(item.planCompleteTime) }}</text>
+            </view>
+          </view>
+          <view class="item-footer">
+            <view class="action-btns">
+              <up-button type="info"
+                         size="small"
+                         plain
+                         text="鐢熶骇杩芥函"
+                         @click="goTraceability(item)"></up-button>
+              <up-button type="info"
+                         size="small"
+                         plain
+                         text="宸ヨ壓璺嚎"
+                         @click="goProcessRoute(item)"></up-button>
+              <up-button type="primary"
+                         size="small"
+                         plain
+                         text="鏉ユ簮"
+                         @click="goSource(item)"></up-button>
+              <up-button type="success"
+                         size="small"
+                         plain
+                         text="棰嗘枡璇︽儏"
+                         @click="goPickingDetail(item)"></up-button>
+            </view>
+          </view>
+        </view>
+      </view>
+      <up-loadmore :status="loadStatus"
+                   v-if="tableData.length >= page.size" />
+    </scroll-view>
+    <view v-else
+          class="no-data">
+      <up-empty mode="data"
+                text="鏆傛棤鐢熶骇璁㈠崟鏁版嵁"></up-empty>
+    </view>
+  </view>
 </template>
 
 <script setup>
-import { ref, reactive, toRefs, getCurrentInstance } from "vue";
-import { onShow } from '@dcloudio/uni-app';
-import dayjs from "dayjs";
-import {schedulingListPage} from "@/api/productionManagement/productionOrder.js";
-import PageHeader from "@/components/PageHeader.vue";
-const { proxy } = getCurrentInstance();
+  import { ref, reactive, toRefs, getCurrentInstance } from "vue";
+  import { onShow } from "@dcloudio/uni-app";
+  import dayjs from "dayjs";
+  import {
+    productOrderListPage,
+    getOrderProcessRouteMain,
+  } from "@/api/productionManagement/productionOrder.js";
+  import { productWorkOrderPage } from "@/api/productionManagement/workOrder.js";
+  import PageHeader from "@/components/PageHeader.vue";
 
-// 鍔犺浇鐘舵��
-const loading = ref(false);
-// 鍒楄〃鏁版嵁
-const tableData = ref([]);
+  const { proxy } = getCurrentInstance();
 
-// 鍒嗛〉閰嶇疆
-const page = reactive({
-	current: -1,
-	size: -1,
-	total: 0,
-});
+  // 鍔犺浇鐘舵��
+  const loading = ref(false);
+  const loadStatus = ref("loadmore");
+  // 鍒楄〃鏁版嵁
+  const tableData = ref([]);
 
-// 鎼滅储琛ㄥ崟鏁版嵁
-const data = reactive({
-	searchForm: {
-		customerName: "",
-	},
-});
-const { searchForm } = toRefs(data);
+  // 鍒嗛〉閰嶇疆
+  const page = reactive({
+    current: 1,
+    size: 10,
+    total: 0,
+  });
 
-// 閫氱敤鎻愮ず鍑芥暟
-const showLoadingToast = (message) => {
-	uni.showLoading({
-		title: message,
-		mask: true
-	});
-};
+  // 鎼滅储琛ㄥ崟鏁版嵁
+  const data = reactive({
+    searchForm: {
+      keyword: "",
+    },
+  });
+  const { searchForm } = toRefs(data);
 
-const closeToast = () => {
-	uni.hideLoading();
-};
+  // 杩斿洖涓婁竴椤�
+  const goBack = () => {
+    uni.navigateBack();
+  };
 
-// 杩斿洖涓婁竴椤�
-const goBack = () => {
-	uni.navigateBack();
-};
+  // 鏍煎紡鍖栨棩鏈�
+  const formatDate = date => {
+    return date ? dayjs(date).format("YYYY-MM-DD") : "-";
+  };
 
-// 鏌ヨ鍒楄〃
-const handleQuery = () => {
-	page.current = 1;
-	tableData.value = []; // 閲嶇疆鍒楄〃鏁版嵁
-	getList();
-};
+  // 鑾峰彇鐘舵�佹枃鏈�
+  const getStatusText = status => {
+    const statusMap = {
+      1: "寰呭紑濮�",
+      2: "杩涜涓�",
+      3: "宸插畬鎴�",
+      4: "宸插彇娑�",
+      5: "宸茬粨鏉�",
+    };
+    return statusMap[status] || "鏈煡";
+  };
 
-// 鑾峰彇鍒楄〃鏁版嵁
-const getList = () => {
-	loading.value = true;
-	showLoadingToast('鍔犺浇涓�...');
-	
-	// 鏋勯�犺姹傚弬鏁�
-	const params = { ...searchForm.value, ...page };
-	
-	schedulingListPage(params).then((res) => {
-		loading.value = false;
-		closeToast();
-		tableData.value = res.data.records || [];
-	}).catch(() => {
-		loading.value = false;
-		closeToast();
-		uni.showToast({
-			title: '鍔犺浇澶辫触',
-			icon: 'error'
-		});
-	});
-};
+  // 鑾峰彇鐘舵�佺被鍨�
+  const getStatusType = status => {
+    const typeMap = {
+      1: "primary",
+      2: "warning",
+      3: "success",
+      4: "info",
+      5: "error",
+    };
+    return typeMap[status] || "info";
+  };
 
-// 椤甸潰鏄剧ず鏃跺姞杞芥暟鎹�
-onShow(() => {
-	// 鍔犺浇鍒楄〃鏁版嵁
-	getList();
-});
+  // 瀹屾垚杩涘害鐧惧垎姣�
+  const toProgressPercentage = val => {
+    const n = Number(val);
+    if (!Number.isFinite(n)) return 0;
+    if (n <= 0) return 0;
+    if (n >= 100) return 100;
+    return Math.round(n);
+  };
+
+  // 杩涘害鏉¢鑹�
+  const progressColor = percentage => {
+    const p = toProgressPercentage(percentage);
+    if (p < 30) return "#f56c6c";
+    if (p < 50) return "#e6a23c";
+    if (p < 80) return "#409eff";
+    return "#67c23a";
+  };
+
+  // 鏌ヨ鍒楄〃
+  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,
+      npsNo: searchForm.value.keyword,
+      productName: searchForm.value.keyword,
+    };
+
+    productOrderListPage(params)
+      .then(async res => {
+        const records = res.data.records || [];
+
+        // 涓烘瘡涓鍗曞苟琛屾煡璇㈠伐搴忚繘搴�
+        const processPromises = records.map(async item => {
+          if (item.npsNo) {
+            try {
+              const workOrderRes = await productWorkOrderPage({
+                npsNo: item.npsNo,
+                size: 100,
+              });
+              const workOrders = workOrderRes.data.records || [];
+              const processRouteStatus = workOrders.map(wo => ({
+                name: wo.operationName || "鏈煡宸ュ簭",
+                percentage:
+                  Number(wo.completionStatus) > 100
+                    ? 100
+                    : Number(wo.completionStatus || 0),
+              }));
+              return { ...item, processRouteStatus };
+            } catch (error) {
+              console.error(`鑾峰彇宸ュ崟 ${item.npsNo} 杩涘害澶辫触:`, error);
+              return { ...item, processRouteStatus: [] };
+            }
+          }
+          return { ...item, processRouteStatus: [] };
+        });
+
+        const updatedRecords = await Promise.all(processPromises);
+
+        loading.value = false;
+        if (page.current === 1) {
+          tableData.value = updatedRecords;
+        } else {
+          tableData.value = [...tableData.value, ...updatedRecords];
+        }
+
+        if (updatedRecords.length < page.size) {
+          loadStatus.value = "nomore";
+        } else {
+          loadStatus.value = "loadmore";
+        }
+        page.total = res.data.total || 0;
+      })
+      .catch(() => {
+        loading.value = false;
+        loadStatus.value = "loadmore";
+        uni.showToast({
+          title: "鍔犺浇澶辫触",
+          icon: "error",
+        });
+      });
+  };
+
+  // 璺宠浆宸ヨ壓璺嚎 (BOM)
+  const goProcessRoute = item => {
+    getOrderProcessRouteMain(item.id)
+      .then(res => {
+        const data = res.data || {};
+        if (!data.id) {
+          uni.showToast({ title: "鏈壘鍒板伐鑹鸿矾绾�", icon: "none" });
+          return;
+        }
+        uni.navigateTo({
+          url: `/pages/productionManagement/processRoute/items?id=${
+            data.id
+          }&bomId=${data.orderBomId}&processRouteCode=${
+            data.processRouteCode || ""
+          }&productName=${encodeURIComponent(
+            item.productName || ""
+          )}&model=${encodeURIComponent(item.model || "")}&orderId=${
+            item.id
+          }&type=order`,
+        });
+      })
+      .catch(() => {
+        uni.showToast({ title: "鑾峰彇璺嚎澶辫触", icon: "none" });
+      });
+  };
+
+  // 璺宠浆鏉ユ簮
+  const goSource = item => {
+    uni.navigateTo({
+      url: `/pages/productionManagement/productionOrder/source?id=${
+        item.id
+      }&productName=${encodeURIComponent(
+        item.productName
+      )}&model=${encodeURIComponent(item.model)}&quantity=${item.quantity}`,
+    });
+  };
+
+  // 璺宠浆棰嗘枡璇︽儏
+  const goPickingDetail = item => {
+    uni.navigateTo({
+      url: `/pages/productionManagement/productionOrder/pickingDetail?id=${item.id}&npsNo=${item.npsNo}`,
+    });
+  };
+
+  // 璺宠浆鐢熶骇杩芥函
+  const goTraceability = item => {
+    uni.navigateTo({
+      url: `/pages/productionManagement/productionTraceability/index?npsNo=${item.npsNo}`,
+    });
+  };
+
+  // 椤甸潰鏄剧ず鏃跺姞杞芥暟鎹�
+  onShow(() => {
+    handleQuery();
+  });
 </script>
 
 <style scoped lang="scss">
-@import '@/styles/sales-common.scss';
+  @import "@/styles/sales-common.scss";
 
-// 鐢熶骇璁㈠崟椤甸潰鏍峰紡
-.production-order {
-	min-height: 100vh;
-	background: #f8f9fa;
-	position: relative;
-}
+  .production-order {
+    min-height: 100vh;
+    background: #f8f9fa;
+    display: flex;
+    flex-direction: column;
+  }
 
-// 閲嶅啓閮ㄥ垎鏍峰紡浠ラ�傞厤鐢熶骇璁㈠崟
-.ledger-item {
-	.detail-value.highlight {
-		color: #ff6b35;
-		font-weight: 600;
-	}
-}
+  .list-container {
+    flex: 1;
+    height: 0;
+  }
 
-// 閫傞厤 uView 缁勪欢鏍峰紡
-:deep(.up-input) {
-	background: transparent;
-}
+  .ledger-item {
+    background: #fff;
+    margin: 20rpx;
+    padding: 24rpx;
+    border-radius: 16rpx;
+    box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
 
-:deep(.up-datetime-picker) {
-	width: 100%;
-}
+    .item-header {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding-bottom: 12rpx;
+
+      .item-left {
+        display: flex;
+        align-items: center;
+
+        .document-icon {
+          width: 44rpx;
+          height: 44rpx;
+          background: #3c9cff;
+          border-radius: 10rpx;
+          display: flex;
+          justify-content: center;
+          align-items: center;
+          margin-right: 20rpx;
+        }
+
+        .item-id {
+          font-size: 30rpx;
+          font-weight: bold;
+          color: #333;
+        }
+      }
+    }
+
+    .item-details {
+      padding: 16rpx 0;
+
+      .detail-row {
+        display: flex;
+        justify-content: space-between;
+        align-items: flex-start;
+        margin-bottom: 16rpx;
+
+        .detail-label {
+          font-size: 26rpx;
+          color: #999;
+          min-width: 140rpx;
+        }
+
+        .detail-value {
+          font-size: 26rpx;
+          color: #333;
+          text-align: right;
+
+          &.font-bold {
+            font-weight: bold;
+          }
+        }
+
+        .progress-box {
+          flex: 1;
+          margin-left: 40rpx;
+
+          .progress-text {
+            font-size: 22rpx;
+            color: #999;
+            margin-top: 4rpx;
+            display: block;
+            text-align: right;
+          }
+        }
+
+        &.process-row {
+          flex-direction: column;
+          margin: 20rpx 0;
+
+          .process-scroll {
+            width: 100%;
+            margin-top: 16rpx;
+
+            .process-container {
+              display: flex;
+              align-items: flex-start;
+              padding: 10rpx 0;
+              min-height: 120rpx;
+
+              .process-item {
+                display: flex;
+                align-items: center;
+
+                .process-node {
+                  display: flex;
+                  flex-direction: column;
+                  align-items: center;
+                  width: 100rpx;
+
+                  .node-circle {
+                    width: 60rpx;
+                    height: 60rpx;
+                    border-radius: 50%;
+                    border: 2rpx solid #3c9cff;
+                    display: flex;
+                    align-items: center;
+                    justify-content: center;
+                    background: #fff;
+                    margin-bottom: 8rpx;
+
+                    .node-percentage {
+                      font-size: 18rpx;
+                      color: #3c9cff;
+                      font-weight: bold;
+                    }
+
+                    &.is-complete {
+                      border-color: #52c41a;
+                      background: #f6ffed;
+
+                      .node-percentage {
+                        color: #52c41a;
+                      }
+                    }
+                  }
+
+                  .node-name {
+                    font-size: 20rpx;
+                    color: #666;
+                    text-align: center;
+                    width: 120rpx;
+                    white-space: nowrap;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                  }
+                }
+
+                .node-line {
+                  width: 40rpx;
+                  height: 2rpx;
+                  background: #e8e8e8;
+                  margin: -30rpx 0 0 0;
+                }
+              }
+
+              .no-process {
+                font-size: 24rpx;
+                color: #ccc;
+              }
+            }
+          }
+        }
+      }
+    }
+
+    .item-footer {
+      padding-top: 20rpx;
+      border-top: 1rpx solid #f0f0f0;
+      display: flex;
+      justify-content: flex-end;
+
+      .action-btns {
+        display: flex;
+        gap: 20rpx;
+      }
+    }
+  }
+
+  .no-data {
+    padding-top: 200rpx;
+  }
 </style>

--
Gitblit v1.9.3