From c6b0f9372c610473a2e8e85e11178d371733a410 Mon Sep 17 00:00:00 2001
From: 张诺 <zhang_12370@163.com>
Date: 星期一, 27 四月 2026 09:09:28 +0800
Subject: [PATCH] feat(productionReport): 添加报工审核记录查看功能
---
src/pages/productionManagement/productionReport/index.vue | 344 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 316 insertions(+), 28 deletions(-)
diff --git a/src/pages/productionManagement/productionReport/index.vue b/src/pages/productionManagement/productionReport/index.vue
index e8b3967..f5f345c 100644
--- a/src/pages/productionManagement/productionReport/index.vue
+++ b/src/pages/productionManagement/productionReport/index.vue
@@ -30,7 +30,7 @@
lower-threshold="80"
@scrolltolower="loadMore"
>
- <view v-for="(item, index) in tableData" :key="item.id || index" class="ledger-item">
+ <view v-for="(item, index) in tableData" :key="item.id || index" class="ledger-item" @click="showTransferCard(item)">
<view class="item-header">
<view class="item-left">
<view class="document-icon">
@@ -87,20 +87,20 @@
</view>
</view>
- <view class="item-actions" v-if="!item.endProductTime">
+ <view class="item-actions" v-if="!isEnded(item)">
<up-button
text="寮�濮嬫姤宸�"
size="mini"
type="primary"
:disabled="!canStartProduction(item) || startSubmittingId === item.id"
- @click="handleStartProduction(item)"
+ @click.stop="handleStartProduction(item)"
/>
<up-button
text="缁撴潫鎶ュ伐"
size="mini"
type="success"
:disabled="!canEndProduction(item)"
- @click="openEndReport(item)"
+ @click.stop="openEndReport(item)"
/>
</view>
</view>
@@ -114,15 +114,64 @@
<!-- 娴佽浆鍗″脊绐� -->
<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"
- />
+ <text class="qr-info" v-if="transferCardRowData">{{ transferCardRowData.workOrderNo || '-' }}</text>
+ <view class="transfer-records">
+ <view class="transfer-records-header">
+ <text class="transfer-records-title">鎶ュ伐瀹℃牳璁板綍</text>
+ <text class="transfer-records-count">鍏� {{ transferCardRecords.length }} 鏉�</text>
+ </view>
+ <view v-if="transferCardLoading" class="transfer-records-loading">鍔犺浇涓�...</view>
+ <view v-else-if="transferCardRecords.length > 0" class="transfer-records-list">
+ <view
+ v-for="(record, index) in transferCardRecords"
+ :key="record.id || index"
+ class="transfer-record-item"
+ >
+ <view class="transfer-record-top">
+ <view class="transfer-record-top-main">
+ <text class="transfer-record-no">{{ record.productNo || `鎶ュ伐璁板綍${index + 1}` }}</text>
+ <text class="transfer-record-sub">
+ {{ record.process || '-' }} / {{ record.deviceName || '-' }}
+ </text>
+ </view>
+ <text class="audit-status-tag" :class="`audit-status-${getAuditStatusType(record.auditStatus)}`">
+ {{ getAuditStatusLabel(record.auditStatus) }}
+ </text>
+ </view>
+ <view class="transfer-record-grid">
+ <view
+ v-for="field in transferRecordFields"
+ :key="field.prop"
+ class="transfer-record-cell"
+ :class="{ 'is-wide': field.wide }"
+ >
+ <text class="transfer-record-label">{{ field.label }}</text>
+ <view v-if="field.prop === 'teamNames'" class="transfer-record-content">
+ <view v-if="getTeamNameList(record.teamNames).length > 0" class="transfer-tag-list">
+ <text
+ v-for="name in getTeamNameList(record.teamNames)"
+ :key="name"
+ class="transfer-name-tag"
+ >
+ {{ name }}
+ </text>
+ </view>
+ <text v-else class="transfer-record-value">-</text>
+ </view>
+ <view v-else-if="field.prop === 'auditStatus'" class="transfer-record-content">
+ <text class="audit-status-tag" :class="`audit-status-${getAuditStatusType(record.auditStatus)}`">
+ {{ getAuditStatusLabel(record.auditStatus) }}
+ </text>
+ </view>
+ <text v-else class="transfer-record-value">
+ {{ formatTransferRecordValue(record, field.prop) }}
+ </text>
+ </view>
+ </view>
+ </view>
+ </view>
+ <view v-else class="transfer-records-empty">鏆傛棤鎶ュ伐瀹℃牳璁板綍</view>
</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>
@@ -274,7 +323,7 @@
<script setup>
import { ref, reactive, toRefs, computed, getCurrentInstance } from "vue";
import { onShow, onLoad, onReachBottom } from "@dcloudio/uni-app";
-import { productWorkOrderPage, addProductMain, startProduction, getProductWorkOrderById } from "@/api/productionManagement/productionReporting.js";
+import { productWorkOrderPage, addProductMain, startProduction, getProductWorkOrderById,getProductionProductMain } from "@/api/productionManagement/productionReporting.js";
import { userListNoPageByTenantId } from "@/api/system/user.js";
import PageHeader from "@/components/PageHeader.vue";
import FilesDia from "./components/filesDia.vue";
@@ -287,6 +336,28 @@
const loadStatus = ref('loadmore');
const transferCardVisible = ref(false);
const transferCardRowData = ref(null);
+const transferCardLoading = ref(false);
+const transferCardRecords = ref([]);
+const auditStatusOptions = ref([
+ { label: "鏈鏍�", value: 0 },
+ { label: "閫氳繃", value: 1 },
+ { label: "涓嶉�氳繃", value: 2 },
+]);
+const transferRecordFields = [
+ { label: "鎶ュ伐浜哄憳", prop: "teamNames", wide: true },
+ { label: "瀹℃牳浜�", prop: "auditUserName" },
+ { label: "鏈�缁堝鏍镐汉", prop: "sureAuditUserName" },
+ { label: "宸ュ崟缂栧彿", prop: "workOrderNo" },
+ { label: "璁㈠崟缂栧彿", prop: "salesContractNo" },
+ { label: "浜у搧鍚嶇О", prop: "productName" },
+ { label: "浜у搧瑙勬牸鍨嬪彿", prop: "productModelName" },
+ { label: "浜у嚭鏁伴噺", prop: "quantity" },
+ { label: "鎶ュ簾鏁伴噺", prop: "scrapQty" },
+ { label: "鍗曚綅", prop: "unit" },
+ { label: "瀹℃牳鐘舵��", prop: "auditStatus" },
+ { label: "澶囨敞淇℃伅", prop: "auditOpinion", wide: true },
+ { label: "鍒涘缓鏃堕棿", prop: "createTime", wide: true },
+];
const workOrderFilesRef = ref(null);
const startSubmittingId = ref(null);
@@ -339,7 +410,7 @@
const data = reactive({
searchForm: {
- workOrderNo: "",
+ workOrderId: "",
},
});
const { searchForm } = toRefs(data);
@@ -450,37 +521,96 @@
return Math.round(n);
};
-const showTransferCard = (row) => {
- transferCardRowData.value = row;
- transferCardVisible.value = true;
+const getAuditStatusLabel = (val) => {
+ const target = auditStatusOptions.value.find(item => Number(item.value) === Number(val));
+ return target?.label || "鏈煡";
};
-const openWorkOrderFiles = (row) => {
- workOrderFilesRef.value?.openDialog(row);
+const getAuditStatusType = (val) => {
+ const typeMap = { 0: "info", 1: "success", 2: "danger" };
+ return typeMap[Number(val)] || "default";
+};
+
+const getTeamNameList = (val) => {
+ if (!val) return [];
+ return String(val)
+ .split(",")
+ .map(item => item.trim())
+ .filter(Boolean);
+};
+
+const formatTransferRecordValue = (record, prop) => {
+ if (prop === "auditStatus") {
+ return getAuditStatusLabel(record?.[prop]);
+ }
+
+ const value = record?.[prop];
+ if (value === null || value === undefined || value === "") {
+ return "-";
+ }
+
+ return String(value);
+};
+
+const getTransferCardParams = (row) => {
+ const params = {
+ current: 1,
+ size: 100,
+ };
+
+ if (row?.id != null) {
+ params.workOrderId = row.id;
+ }
+ if (row?.workOrderNo) {
+ params.workOrderNo = row.workOrderNo;
+ }
+ if (row?.productMainId != null) {
+ params.productMainId = row.productMainId;
+ }
+
+ return params;
+};
+
+const showTransferCard = async (row) => {
+ transferCardRowData.value = row;
+ transferCardVisible.value = true;
+ transferCardRecords.value = [];
+ transferCardLoading.value = true;
+
+ try {
+ const res = await getProductionProductMain(getTransferCardParams(row));
+ transferCardRecords.value = res?.data?.records || res?.records || [];
+ } catch {
+ transferCardRecords.value = [];
+ showToast("鍔犺浇鎶ュ伐瀹℃牳璁板綍澶辫触");
+ } finally {
+ transferCardLoading.value = false;
+ }
};
const getPendingQty = (row) => {
const plan = Number(row?.planQuantity) || 0;
const complete = Number(row?.completeQuantity) || 0;
- return plan - complete;
+ return Math.max(plan - complete, 0);
};
const isStarted = (row) => {
- if (row?.startProductTime && !row?.endProductTime) return true;
- if (String(row?.reportWork) === "1" && !row?.endProductTime) return true;
- return false;
+ if (!row?.id) return false;
+ if (Number(row?.completeQuantity) > 0) return true;
+ if (row?.startProductTime) return true;
+ return String(row?.reportWork) === "1";
};
const isEnded = (row) => {
- return Boolean(row?.endProductTime);
+ return getPendingQty(row) <= 0;
};
const canEndProduction = (row) => {
if (!row?.id) return false;
if (getPendingQty(row) <= 0) return false;
if (isEnded(row)) return false;
- if (!isStarted(row)) return false;
- return true;
+ return isStarted(row);
+
};
// 鍒ゆ柇鏄惁鍙互寮�濮嬫姤宸�
@@ -489,8 +619,8 @@
if (getPendingQty(row) <= 0) return false;
if (isEnded(row)) return false;
if (isStarted(row)) return false;
- if (!canStartProductionByUserIds(userStore.id, row)) return false;
- return true;
+ return canStartProductionByUserIds(userStore.id, row);
+
};
// 鏍规嵁userIds鍒ゆ柇鏄惁鏈夌敤鎴峰彲浠ユ姤宸�
@@ -747,6 +877,164 @@
}
}
+.qr-popup {
+ width: 620rpx;
+ max-width: 88vw;
+ max-height: 80vh;
+ padding: 32rpx 28rpx;
+ background: #fff;
+ border-radius: 20rpx;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ box-sizing: border-box;
+}
+.qr-title {
+ font-size: 30rpx;
+ font-weight: 600;
+ color: #222;
+}
+.qr-box {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ margin-top: 24rpx;
+}
+.qr-info {
+ margin-top: 16rpx;
+ font-size: 26rpx;
+ color: #666;
+}
+.transfer-records {
+ width: 100%;
+ margin-top: 28rpx;
+}
+.transfer-records-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 16rpx;
+ margin-bottom: 16rpx;
+}
+.transfer-records-title {
+ font-size: 26rpx;
+ font-weight: 600;
+ color: #222;
+}
+.transfer-records-count {
+ font-size: 22rpx;
+ color: #8a8a8a;
+}
+.transfer-records-loading,
+.transfer-records-empty {
+ padding: 28rpx 0;
+ font-size: 24rpx;
+ color: #8a8a8a;
+ text-align: center;
+}
+.transfer-records-list {
+ max-height: 420rpx;
+ overflow: auto;
+}
+.transfer-record-item {
+ padding: 20rpx 22rpx;
+ border-radius: 16rpx;
+ background: #f7f8fa;
+}
+.transfer-record-item + .transfer-record-item {
+ margin-top: 16rpx;
+}
+.transfer-record-top {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ gap: 24rpx;
+}
+.transfer-record-top-main {
+ display: flex;
+ flex-direction: column;
+ gap: 8rpx;
+ min-width: 0;
+}
+.transfer-record-no {
+ font-size: 28rpx;
+ font-weight: 600;
+ color: #222;
+ word-break: break-all;
+}
+.transfer-record-sub {
+ font-size: 22rpx;
+ color: #8a8a8a;
+ word-break: break-all;
+}
+.transfer-record-grid {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 16rpx;
+ margin-top: 18rpx;
+}
+.transfer-record-cell {
+ width: calc(50% - 8rpx);
+ min-width: 0;
+}
+.transfer-record-cell.is-wide {
+ width: 100%;
+}
+.transfer-record-label {
+ display: block;
+ margin-bottom: 8rpx;
+ font-size: 22rpx;
+ color: #8a8a8a;
+}
+.transfer-record-content {
+ min-height: 36rpx;
+}
+.transfer-record-value {
+ display: block;
+ font-size: 24rpx;
+ color: #222;
+ word-break: break-all;
+}
+.transfer-tag-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 10rpx;
+}
+.transfer-name-tag {
+ padding: 6rpx 14rpx;
+ border-radius: 999rpx;
+ background: #e9f2ff;
+ color: #2f6bff;
+ font-size: 22rpx;
+}
+.audit-status-tag {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 40rpx;
+ padding: 0 16rpx;
+ border-radius: 999rpx;
+ font-size: 22rpx;
+ box-sizing: border-box;
+}
+.audit-status-info {
+ background: #edf1f5;
+ color: #6b7280;
+}
+.audit-status-success {
+ background: #e9f9ef;
+ color: #16a34a;
+}
+.audit-status-danger {
+ background: #feeeee;
+ color: #dc2626;
+}
+.audit-status-default {
+ background: #f4f4f5;
+ color: #606266;
+}
+
.report-modal {
background: #fff;
max-height: 85vh;
--
Gitblit v1.9.3