From c5842658c8bc44bd604090192c0e8857bb22e596 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 06 五月 2026 16:01:23 +0800
Subject: [PATCH] 生产追溯模块开发,及生产订单跳转生产追溯
---
src/pages.json | 7
src/pages/productionManagement/productionTraceability/index.vue | 947 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/pages/works.vue | 9
src/api/productionManagement/productionOrder.js | 9
src/pages/productionManagement/productionOrder/index.vue | 18
5 files changed, 987 insertions(+), 3 deletions(-)
diff --git a/src/api/productionManagement/productionOrder.js b/src/api/productionManagement/productionOrder.js
index bbe6162..3038550 100644
--- a/src/api/productionManagement/productionOrder.js
+++ b/src/api/productionManagement/productionOrder.js
@@ -10,6 +10,15 @@
});
}
+// 鐢熶骇璁㈠崟婧簮璇︽儏
+export function getOrderDetail(npsNo) {
+ return request({
+ url: "/productionOrder/ordeDetail",
+ method: "get",
+ params: { npsNo },
+ });
+}
+
// 鑾峰彇鐢熶骇璁㈠崟鏉ユ簮鏁版嵁
export function getProductOrderSource(id) {
return request({
diff --git a/src/pages.json b/src/pages.json
index 55521e4..78e18df 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -866,6 +866,13 @@
}
},
{
+ "path": "pages/productionManagement/productionTraceability/index",
+ "style": {
+ "navigationBarTitleText": "鐢熶骇杩芥函",
+ "navigationStyle": "custom"
+ }
+ },
+ {
"path": "pages/inventoryManagement/receiptManagement/index",
"style": {
"navigationBarTitleText": "鑷畾涔夊叆搴�",
diff --git a/src/pages/productionManagement/productionOrder/index.vue b/src/pages/productionManagement/productionOrder/index.vue
index 9cea91f..5f31fb1 100644
--- a/src/pages/productionManagement/productionOrder/index.vue
+++ b/src/pages/productionManagement/productionOrder/index.vue
@@ -100,17 +100,22 @@
<view class="item-footer">
<view class="action-btns">
<up-button type="info"
- size="mini"
+ 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="mini"
+ size="small"
plain
text="鏉ユ簮"
@click="goSource(item)"></up-button>
<up-button type="success"
- size="mini"
+ size="small"
plain
text="棰嗘枡璇︽儏"
@click="goPickingDetail(item)"></up-button>
@@ -340,6 +345,13 @@
});
};
+ // 璺宠浆鐢熶骇杩芥函
+ const goTraceability = item => {
+ uni.navigateTo({
+ url: `/pages/productionManagement/productionTraceability/index?npsNo=${item.npsNo}`,
+ });
+ };
+
// 椤甸潰鏄剧ず鏃跺姞杞芥暟鎹�
onShow(() => {
handleQuery();
diff --git a/src/pages/productionManagement/productionTraceability/index.vue b/src/pages/productionManagement/productionTraceability/index.vue
new file mode 100644
index 0000000..b761cb6
--- /dev/null
+++ b/src/pages/productionManagement/productionTraceability/index.vue
@@ -0,0 +1,947 @@
+<template>
+ <view class="production-traceability">
+ <PageHeader title="鐢熶骇杩芥函"
+ @back="goBack" />
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="search-bar"
+ @click="openNpsNoSelector">
+ <view class="search-input">
+ <text v-if="!selectedNpsNo"
+ class="placeholder">璇烽�夋嫨鐢熶骇璁㈠崟鍙�</text>
+ <text v-else
+ class="value">{{ selectedNpsNoLabel }}</text>
+ </view>
+ <view class="search-button">
+ <up-icon name="arrow-down"
+ size="20"
+ color="#999"></up-icon>
+ </view>
+ </view>
+ </view>
+ <!-- 鍐呭鍖哄煙 -->
+ <view class="content-container"
+ v-if="rowData.productionOrderDto">
+ <!-- 鍩虹淇℃伅 -->
+ <view class="info-card">
+ <view class="card-title">鍩虹淇℃伅</view>
+ <view class="info-grid">
+ <view class="info-item">
+ <text class="label">鐢熶骇璁㈠崟鍙�</text>
+ <text class="value">{{ rowData.productionOrderDto.npsNo || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="label">浜у搧鍚嶇О</text>
+ <text class="value">{{ rowData.productionOrderDto.productName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="label">浜у搧瑙勬牸</text>
+ <text class="value">{{ rowData.productionOrderDto.model || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="label">璁″垝鏁伴噺</text>
+ <text class="value">{{ rowData.productionOrderDto.quantity || 0 }} {{ rowData.productionOrderDto.unit || '' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="label">褰撳墠鐘舵��</text>
+ <up-tag :text="getStatusText(rowData.productionOrderDto.status)"
+ style="width:100rpx"
+ :type="getStatusType(rowData.productionOrderDto.status)"
+ size="mini" />
+ </view>
+ <view class="info-item">
+ <text class="label">瀹㈡埛鍚嶇О</text>
+ <text class="value">{{ rowData.productionOrderDto.customerName || '-' }}</text>
+ </view>
+ <view class="info-item">
+ <text class="label">寮�濮嬫棩鏈�</text>
+ <text class="value">{{ formatDate(rowData.productionOrderDto.startTime) }}</text>
+ </view>
+ <view class="info-item full-width">
+ <text class="label">瀹屾垚杩涘害</text>
+ <view class="progress-container">
+ <up-line-progress :percentage="formatProgress(rowData.productionOrderDto.completionStatus)"
+ :activeColor="progressColor(rowData.productionOrderDto.completionStatus)"
+ height="8"></up-line-progress>
+ <text class="progress-text">{{ formatProgress(rowData.productionOrderDto.completionStatus) }}%</text>
+ </view>
+ </view>
+ </view>
+ </view>
+ <!-- 宸ュ崟淇℃伅 -->
+ <view class="work-order-section"
+ v-if="rowData.productionRecords && rowData.productionRecords.length > 0">
+ <view class="section-title">宸ュ崟淇℃伅</view>
+ <view v-for="(item, index) in rowData.productionRecords"
+ :key="index"
+ class="work-order-card">
+ <view class="card-header">
+ <text class="work-order-no">{{ item.workOrder.workOrderNo }}</text>
+ <text class="progress-tag"
+ :style="{ color: progressColor(item.workOrder.completionStatus) }">{{ item.workOrder.completionStatus || 0 }}%</text>
+ </view>
+ <view class="card-content">
+ <view class="content-row">
+ <text class="label">浜у搧/瑙勬牸锛�</text>
+ <text class="value">{{ item.workOrder.productName }} / {{ item.workOrder.model }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">闇�姹�/瀹屾垚锛�</text>
+ <text class="value">{{ item.workOrder.planQuantity }} / {{ item.workOrder.completeQuantity }}</text>
+ </view>
+ </view>
+ <view class="card-footer">
+ <up-button type="primary"
+ size="small"
+ plain
+ text="鎶ュ伐璁板綍"
+ @click="handleShowReports(item)"></up-button>
+ <up-button type="success"
+ size="small"
+ plain
+ text="璐ㄦ淇℃伅"
+ @click="handleShowQuality(item)"></up-button>
+ </view>
+ </view>
+ </view>
+ <view v-else
+ class="no-data-minor">
+ <up-empty mode="data"
+ text="鏆傛棤宸ュ崟淇℃伅"
+ icon-size="40"></up-empty>
+ </view>
+ </view>
+ <view v-else
+ class="no-data">
+ <up-empty mode="search"
+ text="璇烽�夋嫨鐢熶骇璁㈠崟鍙锋煡鐪嬭拷婧俊鎭�"></up-empty>
+ </view>
+ <!-- 鐢熶骇璁㈠崟鍙烽�夋嫨寮圭獥 -->
+ <up-popup :show="showNpsNoSelector"
+ mode="bottom"
+ @close="showNpsNoSelector = false"
+ round="10">
+ <view class="selector-popup">
+ <view class="popup-header">
+ <text class="popup-title">閫夋嫨鐢熶骇璁㈠崟鍙�</text>
+ <up-icon name="close"
+ size="20"
+ @click="showNpsNoSelector = false"></up-icon>
+ </view>
+ <view class="search-box">
+ <up-search placeholder="杈撳叆鍏抽敭瀛楁悳绱�"
+ v-model="npsNoQuery"
+ :show-action="false"
+ @change="handleNpsNoSearch"
+ @search="handleNpsNoSearch"
+ :loading="npsNoLoading"></up-search>
+ </view>
+ <scroll-view scroll-y
+ class="options-list">
+ <view v-for="item in npsNoOptions"
+ :key="item.id"
+ class="option-item"
+ @click="onSelectNpsNo(item)">
+ <view class="option-main">
+ <text class="nps-no">{{ item.npsNo }}</text>
+ <text class="product-info">{{ item.productName }} / {{ item.model }}</text>
+ </view>
+ <up-icon v-if="selectedNpsNo === item.id"
+ name="checkbox-mark"
+ color="#3c9cff"
+ size="20"></up-icon>
+ </view>
+ <view v-if="npsNoOptions.length === 0"
+ class="no-options">
+ <text>{{ npsNoLoading ? '鍔犺浇涓�...' : '鏆傛棤閫夐」' }}</text>
+ </view>
+ </scroll-view>
+ </view>
+ </up-popup>
+ <!-- 鎶ュ伐璇︽儏寮圭獥 -->
+ <up-popup :show="reportPopupVisible"
+ mode="bottom"
+ @close="reportPopupVisible = false"
+ round="10">
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">鐢熶骇鎶ュ伐璇︽儏</text>
+ <up-icon name="close"
+ size="20"
+ @click="reportPopupVisible = false"></up-icon>
+ </view>
+ <scroll-view scroll-y
+ class="popup-scroll">
+ <view class="detail-info">
+ <view class="info-row"><text class="label">宸ュ崟鍙凤細</text><text class="value">{{ detailData.workOrder.workOrderNo }}</text></view>
+ <view class="info-row"><text class="label">璁″垝/瀹屾垚锛�</text><text class="value">{{ detailData.workOrder.planQuantity }} / {{ detailData.workOrder.completeQuantity }}</text></view>
+ <view class="info-row"><text class="label">瀹為檯鏃堕棿锛�</text><text class="value">{{ formatDate(detailData.workOrder.actualStartTime) }} 鑷� {{ formatDate(detailData.workOrder.actualEndTime) }}</text></view>
+ </view>
+ <view class="list-title">鎶ュ伐鏄庣粏</view>
+ <view v-for="(report, idx) in detailData.reports"
+ :key="idx"
+ class="detail-item">
+ <view class="item-main">
+ <view class="item-row"><text class="label">鎶ュ伐鍗曞彿锛�</text><text class="value">{{ report.productNo }}</text></view>
+ <view class="item-row"><text class="label">鍒涘缓浜猴細</text><text class="value">{{ report.userName }}</text></view>
+ <view class="item-row"><text class="label">鍒涘缓鏃堕棿锛�</text><text class="value">{{ formatDate(report.createTime, '{y}-{m}-{d} {h}:{i}') }}</text></view>
+ </view>
+ <view class="item-actions">
+ <text class="action-link"
+ @click="showParams(report.productionOperationParamList)">鍙傛暟璇︽儏</text>
+ <text class="action-link green"
+ @click="handleShowInput(report.id)">鎶曞叆璇︽儏</text>
+ </view>
+ </view>
+ <view v-if="!detailData.reports || detailData.reports.length === 0"
+ class="no-data-minor">鏆傛棤鎶ュ伐鏄庣粏</view>
+ </scroll-view>
+ </view>
+ </up-popup>
+ <!-- 鎶曞叆璇︽儏寮圭獥 -->
+ <up-popup :show="inputPopupVisible"
+ mode="bottom"
+ @close="inputPopupVisible = false"
+ round="10">
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">鎶曞叆淇℃伅璇︽儏</text>
+ <up-icon name="close"
+ size="20"
+ @click="inputPopupVisible = false"></up-icon>
+ </view>
+ <scroll-view scroll-y
+ class="popup-scroll">
+ <view class="input-list-popup">
+ <view v-for="(item, idx) in inputListData"
+ :key="idx"
+ class="input-item">
+ <view class="input-row"><text class="label">鐗╂枡鍚嶇О锛�</text><text class="value">{{ item.materialName }}</text></view>
+ <view class="input-row"><text class="label">瑙勬牸鍨嬪彿锛�</text><text class="value">{{ item.model }}</text></view>
+ <view class="input-row"><text class="label">鎶曞叆鏁伴噺锛�</text><text class="value">{{ item.quantity }} {{ item.unit }}</text></view>
+ <view class="input-row"><text class="label">鎵规鍙凤細</text><text class="value">{{ item.batchNo }}</text></view>
+ </view>
+ <view v-if="!inputListData || inputListData.length === 0"
+ class="no-data-minor">{{ inputLoading ? '鍔犺浇涓�...' : '鏆傛棤鎶曞叆璁板綍' }}</view>
+ </view>
+ </scroll-view>
+ </view>
+ </up-popup>
+ <!-- 璐ㄦ璇︽儏寮圭獥 -->
+ <up-popup :show="qualityPopupVisible"
+ mode="bottom"
+ @close="qualityPopupVisible = false"
+ round="10">
+ <view class="popup-content">
+ <view class="popup-header">
+ <text class="popup-title">璐ㄦ璇︽儏</text>
+ <up-icon name="close"
+ size="20"
+ @click="qualityPopupVisible = false"></up-icon>
+ </view>
+ <scroll-view scroll-y
+ class="popup-scroll">
+ <view v-for="(record, idx) in qualityRecords"
+ :key="idx"
+ class="quality-record">
+ <view class="record-title">妫�娴嬭褰� {{ idx + 1 }}</view>
+ <view class="info-grid">
+ <view class="info-item"><text class="label">妫�娴嬫棩鏈�</text><text class="value">{{ formatDate(record.createTime) }}</text></view>
+ <view class="info-item"><text class="label">妫�娴嬬粨鏋�</text><up-tag style="width:100rpx"
+ :text="record.checkResult || '寰呮娴�'"
+ :type="record.checkResult === '鍚堟牸' ? 'success' : 'error'"
+ size="mini" /></view>
+ <view class="info-item"><text class="label">妫�楠屽憳</text><text class="value">{{ record.userName }}</text></view>
+ <view class="info-item"><text class="label">鏁伴噺</text><text class="value">{{ record.quantity }} {{ record.unit }}</text></view>
+ </view>
+ <view class="params-table">
+ <view class="table-header">
+ <text class="col">鎸囨爣</text>
+ <text class="col">鏍囧噯鍊�</text>
+ <text class="col">瀹為檯鍊�</text>
+ </view>
+ <view v-for="(param, pIdx) in record.inspectParamList"
+ :key="pIdx"
+ class="table-row">
+ <text class="col">{{ param.parameterItem }}</text>
+ <text class="col">{{ param.standardValue }}</text>
+ <text class="col"
+ :class="{ 'error-text': param.testValue != param.standardValue }">{{ param.testValue }}</text>
+ </view>
+ </view>
+ </view>
+ <view v-if="!qualityRecords || qualityRecords.length === 0"
+ class="no-data-minor">鏆傛棤璐ㄦ璁板綍</view>
+ </scroll-view>
+ </view>
+ </up-popup>
+ <!-- 鍙傛暟璇︽儏寮圭獥 -->
+ <up-modal :show="paramModalVisible"
+ title="鍙傛暟璇︽儏"
+ @confirm="paramModalVisible = false">
+ <view class="modal-content">
+ <view v-for="(param, idx) in currentParams"
+ :key="idx"
+ class="param-row">
+ <text class="label">{{ param.paramName }}锛�</text>
+ <text class="value">{{ param.inputValue }} {{ param.unit && param.unit !== '/' ? param.unit : '' }}</text>
+ </view>
+ <view v-if="!currentParams || currentParams.length === 0"
+ class="no-data-minor">鏆傛棤鍙傛暟鏁版嵁</view>
+ </view>
+ </up-modal>
+ </view>
+</template>
+
+<script setup>
+ import { ref, reactive, computed } from "vue";
+ import { onLoad } from "@dcloudio/uni-app";
+ import {
+ getOrderDetail,
+ productOrderListPage,
+ } from "@/api/productionManagement/productionOrder";
+ import { productionProductInputListPage } from "@/api/productionManagement/productionProductMain";
+ import PageHeader from "@/components/PageHeader.vue";
+ import { parseTime } from "@/utils/ruoyi";
+
+ // 閫夋嫨鍣ㄧ浉鍏�
+ const showNpsNoSelector = ref(false);
+ const npsNoQuery = ref("");
+ const npsNoOptions = ref([]);
+ const npsNoLoading = ref(false);
+ const selectedNpsNo = ref(null);
+ const selectedNpsNoLabel = ref("");
+
+ const rowData = reactive({
+ productionOrderDto: null,
+ productionRecords: [],
+ });
+
+ // 鎶ュ伐璇︽儏
+ const reportPopupVisible = ref(false);
+ const detailData = ref({ workOrder: {}, reports: [] });
+
+ // 鎶曞叆璇︽儏
+ const inputPopupVisible = ref(false);
+ const inputListData = ref([]);
+ const inputLoading = ref(false);
+
+ // 璐ㄦ璇︽儏
+ const qualityPopupVisible = ref(false);
+ const qualityRecords = ref([]);
+
+ // 鍙傛暟璇︽儏
+ const paramModalVisible = ref(false);
+ const currentParams = ref([]);
+
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ const openNpsNoSelector = () => {
+ showNpsNoSelector.value = true;
+ if (npsNoOptions.value.length === 0) {
+ handleNpsNoSearch();
+ }
+ };
+
+ const handleNpsNoSearch = async () => {
+ npsNoLoading.value = true;
+ try {
+ const res = await productOrderListPage({
+ npsNo: npsNoQuery.value || "",
+ pageNum: 1,
+ pageSize: 50,
+ });
+ npsNoOptions.value = res.data?.records || res.rows || [];
+ } catch (error) {
+ console.error(error);
+ } finally {
+ npsNoLoading.value = false;
+ }
+ };
+
+ const onSelectNpsNo = async item => {
+ selectedNpsNo.value = item.id;
+ selectedNpsNoLabel.value = item.npsNo;
+ showNpsNoSelector.value = false;
+
+ uni.showLoading({ title: "鍔犺浇涓�..." });
+ try {
+ const res = await getOrderDetail(item.npsNo);
+ if (res.code === 200 && res.data) {
+ const { productionOrder, workOrderList } = res.data;
+ rowData.productionOrderDto = productionOrder || item;
+ rowData.productionRecords = workOrderList || [];
+ } else {
+ rowData.productionOrderDto = item;
+ rowData.productionRecords = [];
+ }
+ } catch (error) {
+ console.error(error);
+ rowData.productionOrderDto = item;
+ rowData.productionRecords = [];
+ uni.showToast({ title: "鑾峰彇璇︽儏澶辫触", icon: "none" });
+ } finally {
+ uni.hideLoading();
+ }
+ };
+
+ onLoad(async options => {
+ if (options.npsNo) {
+ uni.showLoading({ title: "鍔犺浇涓�..." });
+ try {
+ const res = await productOrderListPage({
+ npsNo: options.npsNo,
+ pageNum: 1,
+ pageSize: 10,
+ });
+ const records = res.data?.records || res.rows || [];
+ if (records.length > 0) {
+ onSelectNpsNo(records[0]);
+ } else {
+ uni.showToast({ title: "鏈壘鍒扮浉鍏宠鍗�", icon: "none" });
+ }
+ } catch (error) {
+ console.error(error);
+ } finally {
+ uni.hideLoading();
+ }
+ }
+ });
+
+ const getStatusText = status => {
+ const statusMap = { 1: "寰呭紑濮�", 2: "杩涜涓�", 3: "宸插畬鎴�", 5: "宸茬粨鏉�" };
+ return statusMap[status] || "宸插彇娑�";
+ };
+
+ const getStatusType = status => {
+ const typeMap = { 1: "primary", 2: "warning", 3: "success", 5: "error" };
+ return typeMap[status] || "info";
+ };
+
+ const formatDate = (date, pattern = "{y}-{m}-{d}") => {
+ return parseTime(date, pattern) || "-";
+ };
+
+ const formatProgress = val => {
+ const p = parseFloat(val || 0);
+ return p >= 100 ? 100 : p;
+ };
+
+ const progressColor = percentage => {
+ if (percentage < 30) return "#f56c6c";
+ if (percentage < 70) return "#e6a23c";
+ return "#67c23a";
+ };
+
+ const handleShowReports = row => {
+ detailData.value = {
+ workOrder: row.workOrder || {},
+ reports: (row.reportList || []).map(r => ({
+ ...r.reportMain,
+ id: r.reportMain.id,
+ productionOperationParamList: r.reportParamList || [],
+ })),
+ };
+ reportPopupVisible.value = true;
+ };
+
+ const handleShowInput = async reportId => {
+ inputPopupVisible.value = true;
+ inputLoading.value = true;
+ inputListData.value = [];
+ try {
+ const res = await productionProductInputListPage({
+ productMainId: reportId,
+ pageNum: 1,
+ pageSize: 100,
+ });
+ inputListData.value = res.data?.records || res.rows || [];
+ } catch (error) {
+ console.error(error);
+ uni.showToast({ title: "鑾峰彇鎶曞叆淇℃伅澶辫触", icon: "none" });
+ } finally {
+ inputLoading.value = false;
+ }
+ };
+
+ const handleShowQuality = row => {
+ const inspects = row.inspectList || [];
+ qualityRecords.value = inspects.map(i => ({
+ ...i.inspect,
+ reportNo: i.reportNo,
+ userName: i.reportMain?.userName || "-",
+ inspectParamList: i.inspectParamList || [],
+ }));
+ qualityPopupVisible.value = true;
+ };
+
+ const showParams = params => {
+ currentParams.value = params || [];
+ paramModalVisible.value = true;
+ };
+</script>
+
+<style scoped lang="scss">
+ @import "@/styles/procurement-common.scss";
+
+ .production-traceability {
+ min-height: 100vh;
+ background-color: #f5f7fa;
+ }
+
+ .search-section {
+ background-color: #fff;
+ padding: 20rpx 24rpx;
+ margin-bottom: 20rpx;
+ }
+
+ .search-bar {
+ display: flex;
+ align-items: center;
+ background-color: #f2f2f2;
+ border-radius: 8rpx;
+ padding: 0 20rpx;
+ height: 80rpx;
+
+ .search-input {
+ flex: 1;
+ display: flex;
+ align-items: center;
+
+ .placeholder {
+ font-size: 28rpx;
+ color: #999;
+ }
+
+ .value {
+ font-size: 28rpx;
+ color: #333;
+ font-weight: 500;
+ }
+ }
+
+ .search-button {
+ padding: 0 10rpx;
+ }
+ }
+
+ .selector-popup {
+ background: #fff;
+ padding: 30rpx;
+ max-height: 70vh;
+ display: flex;
+ flex-direction: column;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24rpx;
+
+ .popup-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ }
+ }
+
+ .search-box {
+ margin-bottom: 20rpx;
+ }
+
+ .options-list {
+ flex: 1;
+ overflow: hidden;
+ }
+
+ .option-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 24rpx 0;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .option-main {
+ flex: 1;
+ .nps-no {
+ font-size: 28rpx;
+ font-weight: bold;
+ color: #333;
+ display: block;
+ margin-bottom: 4rpx;
+ }
+ .product-info {
+ font-size: 24rpx;
+ color: #999;
+ }
+ }
+ }
+
+ .no-options {
+ text-align: center;
+ padding: 40rpx;
+ color: #999;
+ font-size: 26rpx;
+ }
+ }
+
+ .content-container {
+ padding: 0 24rpx 40rpx;
+ }
+
+ .info-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 24rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
+
+ .card-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ margin-bottom: 24rpx;
+ padding-left: 16rpx;
+ border-left: 8rpx solid #3c9cff;
+ }
+ }
+
+ .info-grid {
+ display: flex;
+ flex-wrap: wrap;
+
+ .info-item {
+ width: 50%;
+ margin-bottom: 20rpx;
+ display: flex;
+ flex-direction: column;
+
+ &.full-width {
+ width: 100%;
+ }
+
+ .label {
+ font-size: 24rpx;
+ color: #999;
+ margin-bottom: 8rpx;
+ }
+
+ .value {
+ font-size: 28rpx;
+ color: #333;
+ word-break: break-all;
+ }
+ }
+ }
+
+ .progress-container {
+ display: flex;
+ align-items: center;
+ gap: 20rpx;
+
+ up-line-progress {
+ flex: 1;
+ }
+
+ .progress-text {
+ font-size: 24rpx;
+ color: #666;
+ min-width: 60rpx;
+ }
+ }
+
+ .section-title {
+ font-size: 32rpx;
+ font-weight: bold;
+ color: #333;
+ margin: 32rpx 0 20rpx;
+ }
+
+ .work-order-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05);
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 20rpx;
+ padding-bottom: 16rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .work-order-no {
+ font-size: 28rpx;
+ font-weight: bold;
+ color: #3c9cff;
+ }
+
+ .progress-tag {
+ font-size: 28rpx;
+ font-weight: bold;
+ }
+ }
+
+ .card-content {
+ .content-row {
+ margin-bottom: 12rpx;
+ font-size: 26rpx;
+
+ .label {
+ color: #999;
+ }
+
+ .value {
+ color: #333;
+ }
+ }
+ }
+
+ .card-footer {
+ display: flex;
+ justify-content: flex-end;
+ gap: 20rpx;
+ margin-top: 20rpx;
+ }
+ }
+
+ .popup-content {
+ background: #fff;
+ padding: 30rpx;
+ max-height: 80vh;
+ display: flex;
+ flex-direction: column;
+ border-radius: 20rpx 20rpx 0 0;
+
+ .popup-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 30rpx;
+
+ .popup-title {
+ font-size: 34rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+
+ .popup-scroll {
+ flex: 1;
+ overflow: hidden;
+ }
+ }
+
+ .detail-info {
+ background: #f8f9fa;
+ padding: 24rpx;
+ border-radius: 16rpx;
+ margin-bottom: 30rpx;
+ flex-direction: column;
+
+ .info-row {
+ margin-bottom: 12rpx;
+ font-size: 28rpx;
+ display: flex;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ color: #999;
+ min-width: 140rpx;
+ }
+ .value {
+ color: #333;
+ flex: 1;
+ font-weight: 500;
+ }
+ }
+ }
+
+ .list-title {
+ font-size: 30rpx;
+ font-weight: bold;
+ margin-bottom: 20rpx;
+ color: #333;
+ display: flex;
+ align-items: center;
+
+ &::before {
+ content: "";
+ width: 6rpx;
+ height: 28rpx;
+ background: #3c9cff;
+ margin-right: 12rpx;
+ border-radius: 4rpx;
+ }
+ }
+
+ .detail-item {
+ background: #fff;
+ border: 1rpx solid #f0f0f0;
+ border-radius: 12rpx;
+ padding: 24rpx;
+ margin-bottom: 20rpx;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ .item-main {
+ flex: 1;
+ .item-row {
+ font-size: 26rpx;
+ margin-bottom: 8rpx;
+ display: flex;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ color: #999;
+ min-width: 130rpx;
+ }
+ .value {
+ color: #333;
+ flex: 1;
+ }
+ }
+ }
+
+ .item-actions {
+ display: flex;
+ flex-direction: column;
+ gap: 16rpx;
+ padding-left: 20rpx;
+ border-left: 1rpx solid #f0f0f0;
+
+ .action-link {
+ font-size: 26rpx;
+ color: #3c9cff;
+ white-space: nowrap;
+
+ &.green {
+ color: #52c41a;
+ }
+ }
+ }
+ }
+
+ .quality-record {
+ background: #fff;
+ border: 1rpx solid #f0f0f0;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ margin-bottom: 30rpx;
+
+ .record-title {
+ font-size: 30rpx;
+ font-weight: bold;
+ color: #3c9cff;
+ margin-bottom: 24rpx;
+ display: flex;
+ justify-content: space-between;
+ }
+ }
+
+ .params-table {
+ margin-top: 24rpx;
+ border: 1rpx solid #f0f0f0;
+ border-radius: 12rpx;
+ overflow: hidden;
+
+ .table-header {
+ display: flex;
+ background: #f8f9fa;
+ padding: 20rpx 16rpx;
+ font-size: 26rpx;
+ font-weight: bold;
+ color: #666;
+ }
+
+ .table-row {
+ display: flex;
+ padding: 20rpx 16rpx;
+ font-size: 26rpx;
+ border-top: 1rpx solid #f0f0f0;
+ color: #333;
+
+ &:nth-child(even) {
+ background: #fafafa;
+ }
+ }
+
+ .col {
+ flex: 1;
+ text-align: center;
+ word-break: break-all;
+ }
+ }
+
+ .modal-content {
+ padding: 30rpx;
+ .param-row {
+ margin-bottom: 20rpx;
+ font-size: 28rpx;
+ display: flex;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ color: #666;
+ min-width: 160rpx;
+ }
+ .value {
+ color: #333;
+ font-weight: 500;
+ flex: 1;
+ }
+ }
+ }
+
+ .input-list-popup {
+ .input-item {
+ background: #fff;
+ border: 1rpx solid #f0f0f0;
+ border-radius: 12rpx;
+ padding: 20rpx;
+ margin-bottom: 20rpx;
+
+ .input-row {
+ display: flex;
+ font-size: 26rpx;
+ margin-bottom: 8rpx;
+ &:last-child {
+ margin-bottom: 0;
+ }
+ .label {
+ color: #999;
+ min-width: 160rpx;
+ }
+ .value {
+ color: #333;
+ flex: 1;
+ }
+ }
+ }
+ }
+
+ .error-text {
+ color: #f56c6c;
+ font-weight: bold;
+ }
+
+ .no-data-minor {
+ text-align: center;
+ padding: 60rpx 40rpx;
+ color: #999;
+ font-size: 28rpx;
+ }
+</style>
diff --git a/src/pages/works.vue b/src/pages/works.vue
index 04aeb3c..c6f3cc6 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -597,6 +597,10 @@
icon: "/static/images/icon/shengchanbaogong1.svg",
label: "鐢熶骇鏍哥畻",
},
+ {
+ icon: "/static/images/icon/shengchanbaogong1.svg",
+ label: "鐢熶骇杩芥函",
+ },
]);
// 璁惧绠$悊鍔熻兘鏁版嵁
@@ -870,6 +874,11 @@
url: "/pages/productionManagement/productionAccounting/index",
});
break;
+ case "鐢熶骇杩芥函":
+ uni.navigateTo({
+ url: "/pages/productionManagement/productionTraceability/index",
+ });
+ break;
case "璁惧鍙拌处":
uni.navigateTo({
url: "/pages/equipmentManagement/ledger/index",
--
Gitblit v1.9.3