From 8a67b9a356a75423372a4cb62aa1408b134c89d9 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 06 五月 2026 16:27:21 +0800
Subject: [PATCH] 工序生产实况模块开发
---
src/pages.json | 7 +
src/api/productionManagement/workOrder.js | 9 +
src/pages/works.vue | 13 +
src/pages/productionManagement/processStatistics/index.vue | 370 ++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 399 insertions(+), 0 deletions(-)
diff --git a/src/api/productionManagement/workOrder.js b/src/api/productionManagement/workOrder.js
index ffdd6a4..d3e0033 100644
--- a/src/api/productionManagement/workOrder.js
+++ b/src/api/productionManagement/workOrder.js
@@ -41,3 +41,12 @@
responseType: "blob",
});
}
+
+// 鑾峰彇宸ュ簭缁熻鏁版嵁
+export function getOperationStatistics(query) {
+ return request({
+ url: "/productionOperationTask/getOperation",
+ method: "get",
+ params: query,
+ });
+}
diff --git a/src/pages.json b/src/pages.json
index 78e18df..f2353d0 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -873,6 +873,13 @@
}
},
{
+ "path": "pages/productionManagement/processStatistics/index",
+ "style": {
+ "navigationBarTitleText": "宸ュ簭鐢熶骇瀹炲喌",
+ "navigationStyle": "custom"
+ }
+ },
+ {
"path": "pages/inventoryManagement/receiptManagement/index",
"style": {
"navigationBarTitleText": "鑷畾涔夊叆搴�",
diff --git a/src/pages/productionManagement/processStatistics/index.vue b/src/pages/productionManagement/processStatistics/index.vue
new file mode 100644
index 0000000..a7cdd95
--- /dev/null
+++ b/src/pages/productionManagement/processStatistics/index.vue
@@ -0,0 +1,370 @@
+<template>
+ <view class="process-statistics">
+ <PageHeader title="宸ュ簭鐢熶骇瀹炲喌"
+ @back="goBack" />
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="date-picker-container"
+ @click="showCalendar = true">
+ <view class="date-input">
+ <up-icon name="calendar"
+ size="20"
+ color="#999"></up-icon>
+ <text class="date-text"
+ :class="{ 'placeholder': !searchForm.startDate }">{{ dateRangeText }}</text>
+ <view v-if="searchForm.startDate"
+ class="clear-icon-wrapper"
+ @click.stop="handleClearDate">
+ <up-icon name="close-circle-fill"
+ size="18"
+ color="#c0c4cc"></up-icon>
+ </view>
+ </view>
+ <view class="search-btn-wrapper">
+ <up-button type="primary"
+ size="small"
+ text="鎼滅储"
+ @click.stop="handleQuery"></up-button>
+ </view>
+ </view>
+ </view>
+ <!-- 缁熻鍗$墖鍒楄〃 -->
+ <scroll-view scroll-y
+ class="stats-list">
+ <view v-if="loading"
+ class="loading-box">
+ <up-loading-icon text="鍔犺浇涓�..."></up-loading-icon>
+ </view>
+ <view v-else-if="statsData.length > 0"
+ class="card-grid">
+ <view v-for="(item, index) in statsData"
+ :key="index"
+ class="stats-card">
+ <view class="card-header">
+ <text class="process-tag">{{ item.name }}</text>
+ <view class="header-details">
+ <view class="detail-row">
+ <text class="label">璁″垝鏁�</text>
+ <text class="value">{{ item.planned }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="label">鑹搧鏁�</text>
+ <text class="value good">{{ item.good }}</text>
+ </view>
+ <view class="detail-row">
+ <text class="label">涓嶈壇鍝�</text>
+ <text class="value bad">{{ item.bad }}</text>
+ </view>
+ </view>
+ </view>
+ <view class="card-body">
+ <view class="main-stat">
+ <text class="big-number">{{ item.total }}</text>
+ <text class="sub-label">鐢熶骇浠诲姟鏁�</text>
+ </view>
+ </view>
+ <view class="card-footer">
+ <view class="progress-section">
+ <view class="progress-header">
+ <text class="progress-label">鐢熶骇杩涘害</text>
+ <text class="percentage-text">{{ item.percentage }}%</text>
+ </view>
+ <up-line-progress :percentage="Math.min(item.percentage, 100)"
+ :activeColor="getProgressColor(item.percentage)"
+ :show-text="false"
+ height="8"></up-line-progress>
+ </view>
+ </view>
+ </view>
+ </view>
+ <view v-else
+ class="no-data">
+ <up-empty mode="data"
+ text="鏆傛棤宸ュ簭缁熻鏁版嵁"></up-empty>
+ </view>
+ </scroll-view>
+ <!-- 鏃ュ巻閫夋嫨鍣� -->
+ <up-calendar :show="showCalendar"
+ mode="range"
+ :maxDate="maxDate"
+ minDate="2026-01-01"
+ :monthNum="monthNum"
+ @confirm="onDateConfirm"
+ @close="showCalendar = false"></up-calendar>
+ </view>
+</template>
+
+<script setup>
+ import { ref, reactive, onMounted, computed } from "vue";
+ import { getOperationStatistics } from "@/api/productionManagement/workOrder.js";
+ import PageHeader from "@/components/PageHeader.vue";
+ import dayjs from "dayjs";
+
+ const loading = ref(false);
+ const showCalendar = ref(false);
+ const dateRange = ref([]);
+ const maxDate = dayjs().format("YYYY-MM-DD");
+ const monthNum = computed(() => {
+ const min = dayjs("2022-02-01");
+ const max = dayjs(maxDate);
+ return max.diff(min, "month") + 1;
+ });
+ // const minDate = dayjs().subtract(7, "day").format("YYYY-MM-DD");
+
+ const searchForm = reactive({
+ startDate: "",
+ endDate: "",
+ });
+
+ const statsData = ref([]);
+
+ const dateRangeText = computed(() => {
+ if (searchForm.startDate && searchForm.endDate) {
+ return `${searchForm.startDate} 鑷� ${searchForm.endDate}`;
+ }
+ return "璇烽�夋嫨鏃ユ湡鍖洪棿";
+ });
+
+ const goBack = () => {
+ uni.navigateBack();
+ };
+
+ const getProgressColor = percentage => {
+ if (percentage >= 100) return "#67c23a";
+ if (percentage >= 50) return "#3c9cff";
+ if (percentage >= 25) return "#e6a23c";
+ return "#f56c6c";
+ };
+
+ const onDateConfirm = e => {
+ searchForm.startDate = e[0];
+ searchForm.endDate = e[e.length - 1];
+ showCalendar.value = false;
+ handleQuery();
+ };
+
+ const getList = () => {
+ loading.value = true;
+ const params = {
+ startDate: searchForm.startDate,
+ endDate: searchForm.endDate,
+ };
+ getOperationStatistics(params)
+ .then(res => {
+ statsData.value = (res.data || []).map(item => ({
+ name: item.operationName || "-",
+ total: item.productionTaskCount || 0,
+ planned: item.planQuantity || 0,
+ good: item.goodQuantity || 0,
+ bad: item.scrapQty || 0,
+ percentage: Number(item.completionStatus || 0),
+ }));
+ })
+ .finally(() => {
+ loading.value = false;
+ });
+ };
+
+ const handleQuery = () => {
+ getList();
+ };
+
+ const handleClearDate = () => {
+ searchForm.startDate = "";
+ searchForm.endDate = "";
+ handleQuery();
+ };
+
+ onMounted(() => {
+ // 榛樿鏃堕棿缃┖
+ searchForm.startDate = "";
+ searchForm.endDate = "";
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "@/styles/procurement-common.scss";
+
+ .process-statistics {
+ min-height: 100vh;
+ background-color: #f5f7fa;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .search-section {
+ background-color: #fff;
+ padding: 24rpx 30rpx;
+ margin-bottom: 20rpx;
+ box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.02);
+ }
+
+ .date-picker-container {
+ display: flex;
+ align-items: center;
+ width: 100%;
+
+ .date-input {
+ flex: 1;
+ height: 80rpx;
+ background-color: #f5f7fa;
+ border: 1rpx solid #e4e7ed;
+ border-radius: 12rpx;
+ display: flex;
+ align-items: center;
+ padding: 0 24rpx;
+ margin-right: 20rpx;
+ transition: all 0.3s;
+
+ &:active {
+ background-color: #ebedf0;
+ }
+
+ .date-text {
+ font-size: 28rpx;
+ color: #303133;
+ margin-left: 16rpx;
+ flex: 1;
+
+ &.placeholder {
+ color: #c0c4cc;
+ }
+ }
+
+ .clear-icon {
+ padding: 10rpx;
+ margin-right: -10rpx;
+ }
+ }
+
+ .search-btn-wrapper {
+ width: 140rpx;
+ }
+ }
+
+ .stats-list {
+ flex: 1;
+ height: 0;
+ padding: 0 24rpx 40rpx;
+ }
+
+ .loading-box {
+ display: flex;
+ justify-content: center;
+ padding-top: 100rpx;
+ }
+
+ .card-grid {
+ display: flex;
+ flex-direction: column;
+ gap: 24rpx;
+ }
+
+ .stats-card {
+ background: #fff;
+ border-radius: 16rpx;
+ padding: 24rpx;
+ box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.05);
+
+ .card-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ margin-bottom: 30rpx;
+
+ .process-tag {
+ background-color: #e6f7ff;
+ color: #1890ff;
+ padding: 6rpx 16rpx;
+ border-radius: 8rpx;
+ font-size: 26rpx;
+ font-weight: bold;
+ }
+
+ .header-details {
+ display: flex;
+ flex-direction: column;
+ gap: 4rpx;
+
+ .detail-row {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ gap: 12rpx;
+
+ .label {
+ font-size: 22rpx;
+ color: #999;
+ }
+
+ .value {
+ font-size: 24rpx;
+ color: #333;
+ font-weight: bold;
+ min-width: 60rpx;
+ text-align: right;
+
+ &.good {
+ color: #52c41a;
+ }
+ &.bad {
+ color: #f56c6c;
+ }
+ }
+ }
+ }
+ }
+
+ .card-body {
+ padding-bottom: 30rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ .main-stat {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .big-number {
+ font-size: 56rpx;
+ font-weight: bold;
+ color: #333;
+ line-height: 1;
+ }
+
+ .sub-label {
+ font-size: 26rpx;
+ color: #666;
+ margin-top: 12rpx;
+ }
+ }
+ }
+
+ .card-footer {
+ padding-top: 24rpx;
+
+ .progress-section {
+ .progress-header {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 12rpx;
+
+ .progress-label {
+ font-size: 24rpx;
+ color: #999;
+ }
+
+ .percentage-text {
+ font-size: 24rpx;
+ font-weight: bold;
+ color: #333;
+ }
+ }
+ }
+ }
+ }
+
+ .no-data {
+ padding-top: 100rpx;
+ }
+</style>
diff --git a/src/pages/works.vue b/src/pages/works.vue
index c6f3cc6..437e36f 100644
--- a/src/pages/works.vue
+++ b/src/pages/works.vue
@@ -601,6 +601,14 @@
icon: "/static/images/icon/shengchanbaogong1.svg",
label: "鐢熶骇杩芥函",
},
+ {
+ icon: "/static/images/icon/shengchanbaogong1.svg",
+ label: "宸ュ簭鐢熶骇瀹炲喌",
+ },
+ {
+ icon: "/static/images/icon/shengchanbaogong1.svg",
+ label: "宸ュ簭瀹炲喌",
+ },
]);
// 璁惧绠$悊鍔熻兘鏁版嵁
@@ -879,6 +887,11 @@
url: "/pages/productionManagement/productionTraceability/index",
});
break;
+ case "宸ュ簭鐢熶骇瀹炲喌":
+ uni.navigateTo({
+ url: "/pages/productionManagement/processStatistics/index",
+ });
+ break;
case "璁惧鍙拌处":
uni.navigateTo({
url: "/pages/equipmentManagement/ledger/index",
--
Gitblit v1.9.3