From ac1218810d89c8daba0e8a3b516c3164b7ef0b2a Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期三, 04 三月 2026 14:13:11 +0800
Subject: [PATCH] 生产报工定制
---
src/pages/index.vue | 23
src/pages.json | 14
src/api/productionManagement/workOrder.js | 35 +
src/pages/productionManagement/workOrder/index.vue | 784 +++++++++++++++++++++++++++++++
src/pages/productionManagement/workOrder/fileList.vue | 564 ++++++++++++++++++++++
src/api/productionManagement/productWorkOrderFile.js | 29 +
6 files changed, 1,444 insertions(+), 5 deletions(-)
diff --git a/src/api/productionManagement/productWorkOrderFile.js b/src/api/productionManagement/productWorkOrderFile.js
new file mode 100644
index 0000000..9fc04a9
--- /dev/null
+++ b/src/api/productionManagement/productWorkOrderFile.js
@@ -0,0 +1,29 @@
+import request from "@/utils/request";
+
+// 鏌ヨ宸ュ崟闄勪欢鍒楄〃
+export function productWorkOrderFileListPage(query) {
+ return request({
+ url: "/productWorkOrderFile/listPage",
+ method: "get",
+ params: query,
+ });
+}
+
+// 鏂板宸ュ崟闄勪欢
+export function productWorkOrderFileAdd(data) {
+ return request({
+ url: "/productWorkOrderFile/add",
+ method: "post",
+ data,
+ });
+}
+
+// 鍒犻櫎宸ュ崟闄勪欢
+export function productWorkOrderFileDel(data) {
+ return request({
+ url: "/productWorkOrderFile/del",
+ method: "delete",
+ data,
+ });
+}
+
diff --git a/src/api/productionManagement/workOrder.js b/src/api/productionManagement/workOrder.js
new file mode 100644
index 0000000..7e8bd86
--- /dev/null
+++ b/src/api/productionManagement/workOrder.js
@@ -0,0 +1,35 @@
+import request from "@/utils/request";
+
+export function productWorkOrderPage(query) {
+ return request({
+ url: "/productWorkOrder/page",
+ method: "get",
+ params: query,
+ });
+}
+
+export function updateProductWorkOrder(data) {
+ return request({
+ url: "/productWorkOrder/updateProductWorkOrder",
+ method: "post",
+ data: data,
+ });
+}
+
+export function addProductMain(data) {
+ return request({
+ url: "/productionProductMain/addProductMain",
+ method: "post",
+ data: data,
+ });
+}
+
+// 涓嬭浇宸ュ崟娴佽浆鍗★紙杩斿洖鏂囦欢娴侊級
+export function downProductWorkOrder(id) {
+ return request({
+ url: "/productWorkOrder/down",
+ method: "post",
+ data: { id },
+ responseType: "blob",
+ });
+}
diff --git a/src/pages.json b/src/pages.json
index 3448002..09239ca 100644
--- a/src/pages.json
+++ b/src/pages.json
@@ -900,6 +900,20 @@
}
},
{
+ "path": "pages/productionManagement/workOrder/index",
+ "style": {
+ "navigationBarTitleText": "鐢熶骇宸ュ崟",
+ "navigationStyle": "custom"
+ }
+ },
+ {
+ "path": "pages/productionManagement/workOrder/fileList",
+ "style": {
+ "navigationBarTitleText": "鐢熶骇宸ュ崟闄勪欢",
+ "navigationStyle": "custom"
+ }
+ },
+ {
"path": "pages/message",
"style": {
"navigationBarTitleText": "娑堟伅涓績"
diff --git a/src/pages/index.vue b/src/pages/index.vue
index daffbc4..f3d80c5 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -397,10 +397,14 @@
// label: "宸ュ簭鎺掍骇",
// bgColor: "#E91E63",
// },
+ // {
+ // icon: "/static/images/icon/shengchanbaogong@2x.png",
+ // label: "鐢熶骇鎶ュ伐",
+ // bgColor: "#673AB7",
+ // },
{
- icon: "/static/images/icon/shengchanbaogong@2x.png",
+ icon: "/static/images/icon/caigoutaizhang@2x.png",
label: "鐢熶骇鎶ュ伐",
- bgColor: "#673AB7",
},
// {
// icon: "/static/images/icon/shengchanhesuan@2x.png",
@@ -617,8 +621,13 @@
url: "/pages/productionManagement/processScheduling/index",
});
break;
+ // case "鐢熶骇鎶ュ伐":
+ // getcode();
+ // break;
case "鐢熶骇鎶ュ伐":
- getcode();
+ uni.navigateTo({
+ url: "/pages/productionManagement/workOrder/index",
+ });
break;
case "鐢熶骇鏍哥畻":
uni.navigateTo({
@@ -1003,10 +1012,14 @@
// 杩囨护鐢熶骇绠℃帶鑿滃崟
const originalProduction = [
+ // {
+ // icon: "/static/images/icon/shengchanbaogong@2x.png",
+ // label: "鐢熶骇鎶ュ伐",
+ // bgColor: "#673AB7",
+ // },
{
- icon: "/static/images/icon/shengchanbaogong@2x.png",
+ icon: "/static/images/icon/caigoutaizhang@2x.png",
label: "鐢熶骇鎶ュ伐",
- bgColor: "#673AB7",
},
];
const filteredProduction = originalProduction.filter(item => {
diff --git a/src/pages/productionManagement/workOrder/fileList.vue b/src/pages/productionManagement/workOrder/fileList.vue
new file mode 100644
index 0000000..bce3442
--- /dev/null
+++ b/src/pages/productionManagement/workOrder/fileList.vue
@@ -0,0 +1,564 @@
+<template>
+ <view class="file-list-page">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="闄勪欢绠$悊"
+ @back="goBack" />
+ <!-- 闄勪欢鍒楄〃 -->
+ <view class="file-list-container">
+ <view v-if="fileList.length > 0"
+ class="file-list">
+ <view v-for="(file, index) in fileList"
+ :key="file.id || index"
+ class="file-item">
+ <!-- 鏂囦欢鍥炬爣 -->
+ <!-- <view class="file-icon"
+ :class="getFileIconClass(file.fileType)">
+ <up-icon :name="getFileIcon(file.fileType)"
+ size="24"
+ color="#ffffff" />
+ </view> -->
+ <!-- 鏂囦欢淇℃伅 -->
+ <view class="file-info">
+ <text class="file-name">{{ file.name }}</text>
+ <!-- <text class="file-meta">{{ formatFileSize(file.fileSize) }} 路 {{ file.uploadTime || file.createTime }}</text> -->
+ </view>
+ <!-- 鎿嶄綔鎸夐挳 -->
+ <view class="file-actions">
+ <!-- <u-button size="small"
+ type="primary"
+ plain
+ @click="previewFile(file)">棰勮</u-button> -->
+ <u-button size="small"
+ type="info"
+ plain
+ @click="downloadFile(file)">涓嬭浇骞堕瑙�</u-button>
+ <u-button size="small"
+ type="error"
+ plain
+ @click="confirmDelete(file, index)">鍒犻櫎</u-button>
+ </view>
+ </view>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <view v-else
+ class="empty-state">
+ <up-icon name="document"
+ size="64"
+ color="#c0c4cc" />
+ <text class="empty-text">鏆傛棤闄勪欢</text>
+ </view>
+ </view>
+ <!-- <a rel="nofollow"
+ id="downloadLink"
+ href="#"
+ style="display:none;">涓嬭浇鏂囨湰鏂囦欢</a> -->
+ <!-- 涓婁紶鎸夐挳 -->
+ <view class="upload-button"
+ @click="chooseFile">
+ <up-icon name="plus"
+ size="24"
+ color="#ffffff" />
+ <text class="upload-text">涓婁紶闄勪欢</text>
+ </view>
+ </view>
+</template>
+
+<script setup>
+ import { ref, onMounted } from "vue";
+ import PageHeader from "@/components/PageHeader.vue";
+ import config from "@/config";
+ import { getToken } from "@/utils/auth";
+ // import { saveAs } from "file-saver";
+ import {
+ listRuleFiles,
+ delRuleFile,
+ } from "@/api/managementMeetings/rulesRegulationsManagement";
+ import {
+ productWorkOrderFileAdd,
+ productWorkOrderFileDel,
+ productWorkOrderFileListPage,
+ } from "@/api/productionManagement/productWorkOrderFile";
+ import { blobValidate } from "@/utils/ruoyi";
+
+ // 闄勪欢鍒楄〃
+ const fileList = ref([]);
+
+ // 杩斿洖涓婁竴椤�
+ const goBack = () => {
+ uni.navigateBack();
+ };
+ // const request = axios.create({
+ // baseURL: "URL.com",
+ // adapter: axiosAdapterUniapp,
+ // });
+ // 鑾峰彇鏂囦欢鍥炬爣
+ const getFileIcon = fileType => {
+ const iconMap = {
+ doc: "document",
+ docx: "document",
+ xls: "grid",
+ xlsx: "grid",
+ pdf: "document",
+ ppt: "copy",
+ pptx: "copy",
+ txt: "document",
+ jpg: "image",
+ jpeg: "image",
+ png: "image",
+ gif: "image",
+ zip: "folder",
+ rar: "folder",
+ };
+ return iconMap[fileType.toLowerCase()] || "document";
+ };
+
+ // 鑾峰彇鏂囦欢鍥炬爣鏍峰紡绫�
+ const getFileIconClass = fileType => {
+ const colorMap = {
+ doc: "blue",
+ docx: "blue",
+ xls: "green",
+ xlsx: "green",
+ pdf: "red",
+ ppt: "orange",
+ pptx: "orange",
+ txt: "gray",
+ jpg: "purple",
+ jpeg: "purple",
+ png: "purple",
+ gif: "purple",
+ zip: "yellow",
+ rar: "yellow",
+ };
+ return colorMap[fileType.toLowerCase()] || "gray";
+ };
+
+ // 鏍煎紡鍖栨枃浠跺ぇ灏�
+ const formatFileSize = bytes => {
+ if (bytes === 0) return "0 B";
+ const k = 1024;
+ const sizes = ["B", "KB", "MB", "GB"];
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
+ };
+
+ // 閫夋嫨鏂囦欢
+ const chooseFile = () => {
+ uni.chooseImage({
+ count: 9,
+ sizeType: ["original", "compressed"],
+ sourceType: ["album", "camera"],
+ success: res => {
+ console.log(res, "閫夋嫨鍥剧墖鎴愬姛");
+ uploadFiles(res.tempFiles);
+ },
+ fail: err => {
+ console.error("閫夋嫨鍥剧墖澶辫触:", err);
+ showToast("閫夋嫨鏂囦欢澶辫触");
+ },
+ });
+ // uni.chooseFile({
+ // count: 9,
+ // extension: [
+ // ".doc",
+ // ".docx",
+ // ".xls",
+ // ".xlsx",
+ // ".pdf",
+ // ".ppt",
+ // ".pptx",
+ // ".txt",
+ // ".jpg",
+ // ".jpeg",
+ // ".png",
+ // ".gif",
+ // ".zip",
+ // ".rar",
+ // ],
+ // success: res => {
+ // console.log(res, "閫夋嫨鏂囦欢鎴愬姛");
+ // uploadFiles(res.tempFiles);
+ // },
+ // fail: err => {
+ // showToast("閫夋嫨鏂囦欢澶辫触");
+ // },
+ // });
+ };
+
+ // 涓婁紶鏂囦欢
+ const uploadFiles = tempFiles => {
+ console.log(tempFiles, "涓婁紶鏂囦欢1");
+ tempFiles.forEach((tempFile, index) => {
+ // 鏄剧ず涓婁紶涓彁绀�
+ uni.showLoading({
+ title: "涓婁紶涓�...",
+ mask: true,
+ });
+ console.log(tempFile, "涓婁紶鏂囦欢2");
+ // 1. 鐩存帴浣跨敤 uni.uploadFile 涓婁紶鏂囦欢
+ uni.uploadFile({
+ url: config.baseUrl + "/file/upload",
+ filePath: tempFile.path,
+ name: "file",
+ header: {
+ Authorization: "Bearer " + getToken(),
+ },
+ success: uploadRes => {
+ uni.hideLoading();
+ console.log(uploadRes, "涓婁紶鏂囦欢3");
+
+ try {
+ const res = JSON.parse(uploadRes.data);
+ console.log(res, "涓婁紶鏂囦欢4");
+ if (res.code === 200) {
+ // 2. 鎻愬彇鏂囦欢淇℃伅
+ const fileName = tempFile.name
+ ? tempFile.name
+ : tempFile.path.split("/").pop();
+ // const fileType = fileName.split(".").pop();
+ // 3. 鏋勯�犱繚瀛樻枃浠朵俊鎭殑鍙傛暟
+ const saveData = {
+ name: fileName,
+ workOrderId: rulesRegulationsManagementId.value,
+ url: res.data.tempPath || "",
+ };
+ console.log(saveData, "淇濆瓨鏂囦欢淇℃伅鍙傛暟");
+ // 4. 璋冪敤 addRuleFile 鎺ュ彛淇濆瓨鏂囦欢淇℃伅
+ productWorkOrderFileAdd(saveData)
+ .then(addRes => {
+ if (addRes.code === 200) {
+ // 5. 娣诲姞鍒版枃浠跺垪琛�
+ const newFile = {
+ ...addRes.data,
+ uploadTime: new Date().toLocaleString(),
+ };
+ // fileList.value.push(newFile);
+ getFileList();
+ showToast("涓婁紶鎴愬姛");
+ } else {
+ showToast("淇濆瓨鏂囦欢淇℃伅澶辫触");
+ }
+ })
+ .catch(err => {
+ console.error("淇濆瓨鏂囦欢淇℃伅澶辫触:", err);
+ showToast("淇濆瓨鏂囦欢淇℃伅澶辫触");
+ });
+ } else {
+ showToast("鏂囦欢涓婁紶澶辫触");
+ }
+ } catch (e) {
+ console.error("瑙f瀽涓婁紶缁撴灉澶辫触:", e);
+ showToast("涓婁紶澶辫触");
+ }
+ },
+ fail: err => {
+ uni.hideLoading();
+ console.error("涓婁紶澶辫触:", err);
+ showToast("涓婁紶澶辫触");
+ },
+ });
+ });
+ };
+ // 涓嬭浇鏂囦欢
+ const downloadFile = file => {
+ var url =
+ config.baseUrl +
+ "/common/download?fileName=" +
+ encodeURIComponent(file.url) +
+ "&delete=true";
+ console.log(url, "url");
+
+ uni
+ .downloadFile({
+ url: url,
+ responseType: "blob",
+ header: { Authorization: "Bearer " + getToken() },
+ })
+ .then(res => {
+ let osType = uni.getStorageSync("deviceInfo").osName;
+ let filePath = res.tempFilePath;
+ if (osType === "ios") {
+ uni.openDocument({
+ filePath: filePath,
+ showMenu: true,
+ success: res => {
+ resolve(res);
+ },
+ fail: err => {
+ console.log("uni.openDocument--fail");
+ reject(err);
+ },
+ });
+ } else {
+ uni.saveFile({
+ tempFilePath: filePath,
+ success: fileRes => {
+ uni.showToast({
+ icon: "none",
+ mask: true,
+ title:
+ "鏂囦欢宸蹭繚瀛橈細Android/data/uni.UNI720216F/apps/__UNI__720216F/" +
+ fileRes.savedFilePath, //淇濆瓨璺緞
+ duration: 3000,
+ });
+ setTimeout(() => {
+ //鎵撳紑鏂囨。鏌ョ湅
+ uni.openDocument({
+ filePath: fileRes.savedFilePath,
+ success: function (res) {
+ resolve(fileRes);
+ },
+ });
+ }, 3000);
+ },
+ fail: err => {
+ console.log("uni.save--fail");
+ reject(err);
+ },
+ });
+ }
+ // const isBlob = blobValidate(res.data);
+ // if (isBlob) {
+ // const blob = new Blob([res.data], { type: "text/plain" });
+ // const url = URL.createObjectURL(blob);
+ // const downloadLink = document.getElementById("downloadLink");
+ // downloadLink.href = url;
+ // downloadLink.download = file.name;
+ // downloadLink.click();
+ // showToast("涓嬭浇鎴愬姛");
+ // } else {
+ // showToast("涓嬭浇澶辫触");
+ // }
+ })
+ .catch(err => {
+ console.error("涓嬭浇澶辫触:", err);
+ showToast("涓嬭浇澶辫触");
+ });
+ };
+
+ // 纭鍒犻櫎
+ const confirmDelete = (file, index) => {
+ uni.showModal({
+ title: "鍒犻櫎纭",
+ content: `纭畾瑕佸垹闄ら檮浠� "${file.name}" 鍚楋紵`,
+ success: res => {
+ if (res.confirm) {
+ deleteFile(file.id, index);
+ }
+ },
+ });
+ };
+
+ // 鍒犻櫎鏂囦欢
+ const deleteFile = (fileId, index) => {
+ uni.showLoading({
+ title: "鍒犻櫎涓�...",
+ mask: true,
+ });
+
+ productWorkOrderFileDel([fileId])
+ .then(res => {
+ uni.hideLoading();
+ if (res.code === 200) {
+ // fileList.value.splice(index, 1);
+ getFileList();
+ showToast("鍒犻櫎鎴愬姛");
+ } else {
+ showToast("鍒犻櫎澶辫触");
+ }
+ })
+ .catch(err => {
+ uni.hideLoading();
+ showToast("鍒犻櫎澶辫触");
+ });
+ };
+
+ // 鏄剧ず鎻愮ず
+ const showToast = message => {
+ uni.showToast({
+ title: message,
+ icon: "none",
+ });
+ };
+ const rulesRegulationsManagementId = ref("");
+ // 椤甸潰鍔犺浇鏃�
+ onMounted(() => {
+ rulesRegulationsManagementId.value = uni.getStorageSync("workOrderFileId");
+ // 浠� API 鑾峰彇闄勪欢鍒楄〃
+ getFileList();
+ // 浠庢湰鍦板瓨鍌ㄨ幏鍙� rulesRegulationsManagementId
+ });
+
+ // 鑾峰彇闄勪欢鍒楄〃
+ const getFileList = () => {
+ uni.showLoading({
+ title: "鍔犺浇涓�...",
+ mask: true,
+ });
+
+ productWorkOrderFileListPage({
+ workOrderId: rulesRegulationsManagementId.value,
+ current: -1,
+ size: -1,
+ })
+ .then(res => {
+ uni.hideLoading();
+ if (res.code === 200) {
+ fileList.value = res.data.records || [];
+ } else {
+ showToast("鑾峰彇闄勪欢鍒楄〃澶辫触");
+ }
+ })
+ .catch(err => {
+ uni.hideLoading();
+ showToast("鑾峰彇闄勪欢鍒楄〃澶辫触");
+ });
+ };
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+
+ .file-list-page {
+ min-height: 100vh;
+ background: #f8f9fa;
+ padding-bottom: 100rpx;
+ }
+
+ .file-list-container {
+ padding: 20rpx;
+ }
+
+ .file-list {
+ background: #ffffff;
+ border-radius: 8rpx;
+ overflow: hidden;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ }
+
+ .file-item {
+ display: flex;
+ align-items: center;
+ padding: 20rpx;
+ border-bottom: 1rpx solid #f0f0f0;
+
+ &:last-child {
+ border-bottom: none;
+ }
+ }
+
+ .file-icon {
+ width: 56rpx;
+ height: 56rpx;
+ border-radius: 8rpx;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ margin-right: 20rpx;
+
+ &.blue {
+ background: #409eff;
+ }
+
+ &.green {
+ background: #67c23a;
+ }
+
+ &.red {
+ background: #f56c6c;
+ }
+
+ &.orange {
+ background: #e6a23c;
+ }
+
+ &.gray {
+ background: #909399;
+ }
+
+ &.purple {
+ background: #909399;
+ }
+
+ &.yellow {
+ background: #e6a23c;
+ }
+ }
+
+ .file-info {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .file-name {
+ display: block;
+ font-size: 16px;
+ color: #303133;
+ margin-bottom: 8rpx;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ .file-meta {
+ display: block;
+ font-size: 12px;
+ color: #909399;
+ }
+
+ .file-actions {
+ display: flex;
+ gap: 12rpx;
+ }
+
+ .empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 100rpx 0;
+ background: #ffffff;
+ border-radius: 8rpx;
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
+ }
+
+ .empty-text {
+ font-size: 14px;
+ color: #909399;
+ margin-top: 20rpx;
+ }
+
+ .upload-button {
+ position: fixed;
+ bottom: 40rpx;
+ right: 40rpx;
+ width: 130rpx;
+ height: 130rpx;
+ border-radius: 50%;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ box-shadow: 0 4rpx 16rpx rgba(102, 126, 234, 0.4);
+ z-index: 1000;
+ }
+
+ .upload-text {
+ font-size: 10px;
+ color: #ffffff;
+ margin-top: 4rpx;
+ }
+
+ .upload-progress {
+ padding: 40rpx 0;
+ }
+
+ .upload-progress-text {
+ display: block;
+ text-align: center;
+ margin-top: 20rpx;
+ font-size: 14px;
+ color: #606266;
+ }
+</style>
\ No newline at end of file
diff --git a/src/pages/productionManagement/workOrder/index.vue b/src/pages/productionManagement/workOrder/index.vue
new file mode 100644
index 0000000..cafa095
--- /dev/null
+++ b/src/pages/productionManagement/workOrder/index.vue
@@ -0,0 +1,784 @@
+<template>
+ <view class="work-order-page">
+ <!-- 椤甸潰澶撮儴 -->
+ <PageHeader title="鐢熶骇鎶ュ伐" />
+ <!-- 鎼滅储鍖哄煙 -->
+ <view class="search-section">
+ <view class="search-bar">
+ <view class="search-input">
+ <up-input class="search-text"
+ placeholder="璇疯緭鍏ュ伐鍗曠紪鍙�"
+ v-model="searchForm.workOrderNo"
+ @change="handleQuery"
+ clearable />
+ </view>
+ <view class="filter-button"
+ @click="handleQuery">
+ <u-icon name="search"
+ size="24"
+ color="#999"></u-icon>
+ </view>
+ </view>
+ </view>
+ <!-- 宸ュ崟鍒楄〃 -->
+ <view v-if="tableData.length > 0"
+ class="work-order-list">
+ <view v-for="(item, index) in tableData"
+ :key="index"
+ class="work-order-item">
+ <view class="item-header">
+ <view class="item-title">
+ <text class="work-order-no">{{ item.workOrderNo || '鏃犵紪鍙�' }}</text>
+ <up-tag :type="getWorkOrderTypeTag(item.workOrderType)"
+ size="small"
+ class="type-tag">
+ {{ item.workOrderType || '鏈煡' }}
+ </up-tag>
+ </view>
+ <up-tag :type="getCompletionStatusTag(item.completionStatus)"
+ size="small">
+ {{ getCompletionStatusText(item.completionStatus) }}
+ </up-tag>
+ </view>
+ <view class="item-content">
+ <view class="content-row">
+ <text class="label">浜у搧鍚嶇О锛�</text>
+ <text class="value">{{ item.productName || '-' }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">瑙勬牸锛�</text>
+ <text class="value">{{ item.model || '-' }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">鍗曚綅锛�</text>
+ <text class="value">{{ item.unit || '-' }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">宸ュ簭鍚嶇О锛�</text>
+ <text class="value">{{ item.processName || '-' }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">闇�姹傛暟閲忥細</text>
+ <text class="value">{{ item.planQuantity || 0 }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">瀹屾垚鏁伴噺锛�</text>
+ <text class="value">{{ item.completeQuantity || 0 }}</text>
+ </view>
+ <view class="content-row">
+ <text class="label">瀹屾垚杩涘害锛�</text>
+ <view class="progress-container">
+ <!-- <up-progress :percentage="toProgressPercentage(item.completionStatus)"
+ :color="progressColor(toProgressPercentage(item.completionStatus))"
+ :active-color="progressColor(toProgressPercentage(item.completionStatus))"
+ :height="6"
+ :show-percentage="false"
+ class="progress-bar" /> -->
+ <text class="progress-text">{{ toProgressPercentage(item.completionStatus) }}%</text>
+ </view>
+ </view>
+ <view class="content-row">
+ <text class="label">璁″垝鏃堕棿锛�</text>
+ <text class="value">{{ formatDate(item.planStartTime) }} 鑷� {{ formatDate(item.planEndTime) }}</text>
+ </view>
+ <view v-if="item.actualStartTime"
+ class="content-row">
+ <text class="label">瀹為檯鏃堕棿锛�</text>
+ <text class="value">{{ formatDate(item.actualStartTime) }} 鑷� {{ formatDate(item.actualEndTime) }}</text>
+ </view>
+ </view>
+ <view class="item-footer">
+ <u-button size="small"
+ @click="handleEdit(item)">
+ 缂栬緫
+ </u-button>
+ <u-button size="small"
+ @click="viewFileList(item)">
+ 闄勪欢
+ </u-button>
+ <u-button type="primary"
+ size="small"
+ :disabled="item.planQuantity <= 0"
+ @click="showReportDialog(item)">
+ 鎶ュ伐
+ </u-button>
+ </view>
+ </view>
+ </view>
+ <!-- 绌虹姸鎬� -->
+ <view v-else
+ class="no-data">
+ <up-empty mode="data"
+ text="鏆傛棤宸ュ崟鏁版嵁" />
+ </view>
+ <!-- 鍒嗛〉缁勪欢 -->
+ <!-- 缂栬緫鏃堕棿寮圭獥 -->
+ <up-popup v-model:show="editDialogVisible"
+ mode="center"
+ round>
+ <view class="dialog-content">
+ <view class="dialog-header">
+ <text class="dialog-title">缂栬緫鏃堕棿</text>
+ <up-icon name="close"
+ size="20"
+ color="#999"
+ @click="editDialogVisible = false" />
+ </view>
+ <view class="dialog-body">
+ <view class="form-item">
+ <text class="form-label">璁″垝寮�濮嬫椂闂�</text>
+ <view class="fake-input-wrapper"
+ @click="showDatePicker('planStartTime',editrow.planStartTime)">
+ <text class="fake-input-text"
+ :class="{ 'placeholder': !editrow.planStartTime }">
+ {{ editrow.planStartTime || '璇烽�夋嫨璁″垝寮�濮嬫椂闂�' }}
+ </text>
+ <up-icon name="calendar"
+ size="20"
+ color="#999" />
+ </view>
+ </view>
+ <view class="form-item">
+ <text class="form-label">璁″垝缁撴潫鏃堕棿</text>
+ <view class="fake-input-wrapper"
+ @click="showDatePicker('planEndTime',editrow.planEndTime)">
+ <text class="fake-input-text"
+ :class="{ 'placeholder': !editrow.planEndTime }">
+ {{ editrow.planEndTime || '璇烽�夋嫨璁″垝缁撴潫鏃堕棿' }}
+ </text>
+ <up-icon name="calendar"
+ size="20"
+ color="#999" />
+ </view>
+ </view>
+ <view class="form-item">
+ <text class="form-label">瀹為檯寮�濮嬫椂闂�</text>
+ <view class="fake-input-wrapper"
+ @click="showDatePicker('actualStartTime',editrow.actualStartTime)">
+ <text class="fake-input-text"
+ :class="{ 'placeholder': !editrow.actualStartTime }">
+ {{ editrow.actualStartTime || '璇烽�夋嫨瀹為檯寮�濮嬫椂闂�' }}
+ </text>
+ <up-icon name="calendar"
+ size="20"
+ color="#999" />
+ </view>
+ </view>
+ <view class="form-item">
+ <text class="form-label">瀹為檯缁撴潫鏃堕棿</text>
+ <view class="fake-input-wrapper"
+ @click="showDatePicker('actualEndTime',editrow.actualEndTime)">
+ <text class="fake-input-text"
+ :class="{ 'placeholder': !editrow.actualEndTime }">
+ {{ editrow.actualEndTime || '璇烽�夋嫨瀹為檯缁撴潫鏃堕棿' }}
+ </text>
+ <up-icon name="calendar"
+ size="20"
+ color="#999" />
+ </view>
+ </view>
+ </view>
+ <view class="dialog-footer">
+ <u-button type="default"
+ class="footer-btn"
+ @click="editDialogVisible = false">
+ 鍙栨秷
+ </u-button>
+ <u-button type="primary"
+ class="footer-btn"
+ @click="handleUpdate">
+ 纭畾
+ </u-button>
+ </view>
+ </view>
+ </up-popup>
+ <!-- 鎶ュ伐寮圭獥 -->
+ <up-popup v-model:show="reportDialogVisible"
+ mode="center"
+ round
+ style="width: 500px">
+ <view class="dialog-content">
+ <view class="dialog-header">
+ <text class="dialog-title">鎶ュ伐</text>
+ <up-icon name="close"
+ size="20"
+ color="#999"
+ @click="reportDialogVisible = false" />
+ </view>
+ <view class="dialog-body">
+ <view class="form-item">
+ <text class="form-label">寰呯敓浜ф暟閲�</text>
+ <up-input v-model="reportForm.planQuantity"
+ disabled
+ readonly />
+ </view>
+ <view class="form-item">
+ <text class="form-label required">鏈鐢熶骇鏁伴噺</text>
+ <up-input v-model.number="reportForm.quantity"
+ type="number"
+ placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�" />
+ </view>
+ <view class="form-item">
+ <text class="form-label">鎶ュ簾鏁伴噺</text>
+ <up-input v-model.number="reportForm.scrapQty"
+ type="number"
+ placeholder="璇疯緭鍏ユ姤搴熸暟閲�" />
+ </view>
+ <view class="form-item">
+ <text class="form-label">鐝粍淇℃伅</text>
+ <view class="fake-input-wrapper"
+ @click="showUserSheet = true">
+ <text class="fake-input-text"
+ :class="{ 'placeholder': !reportForm.userName }">
+ {{ reportForm.userName || '璇烽�夋嫨鐝粍淇℃伅' }}
+ </text>
+ <up-icon name="arrow-right"
+ size="20"
+ color="#999" />
+ </view>
+ </view>
+ </view>
+ <view class="dialog-footer">
+ <u-button type="default"
+ class="footer-btn"
+ @click="reportDialogVisible = false">
+ 鍙栨秷
+ </u-button>
+ <u-button type="primary"
+ class="footer-btn"
+ @click="handleReport">
+ 纭畾
+ </u-button>
+ </view>
+ </view>
+ </up-popup>
+ <!-- 鏃ユ湡閫夋嫨鍣� -->
+ <!-- <up-popup v-model:show="showDate"
+ mode="date"
+ :start-year="2020"
+ :end-year="2030"
+ @close="showDate = false"
+ @confirm="confirmDate" /> -->
+ <u-datetime-picker :show="showDate"
+ v-model="value1"
+ @close="showDate = false"
+ @confirm="confirmDate"
+ @cancel="showDate = false"
+ mode="date"
+ format="YYYY-MM-DD"></u-datetime-picker>
+ <!-- 鐝粍閫夋嫨 -->
+ <up-action-sheet :show="showUserSheet"
+ :actions="userSheetOptions"
+ @select="selectUser"
+ @close="showUserSheet = false"
+ title="閫夋嫨鐝粍淇℃伅" />
+ </view>
+</template>
+
+<script setup>
+ import { ref, reactive, onMounted, computed } from "vue";
+ import { onShow } from "@dcloudio/uni-app";
+ import PageHeader from "@/components/PageHeader.vue";
+ import dayjs from "dayjs";
+ import {
+ productWorkOrderPage,
+ updateProductWorkOrder,
+ addProductMain,
+ } from "@/api/productionManagement/workOrder.js";
+ import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
+
+ // 鏄剧ず鎻愮ず淇℃伅
+ const showToast = message => {
+ uni.showToast({
+ title: message,
+ icon: "none",
+ });
+ };
+
+ // 鎼滅储琛ㄥ崟
+ const searchForm = ref({
+ workOrderNo: "",
+ });
+
+ // 宸ュ崟鍒楄〃鏁版嵁
+ const tableData = ref([]);
+ const tableLoading = ref(false);
+ const value1 = ref(new Date());
+ // 鍒嗛〉鏁版嵁
+ const page = reactive({
+ current: -1,
+ size: -1,
+ total: 0,
+ });
+
+ // 缂栬緫寮圭獥
+ const editDialogVisible = ref(false);
+ const editrow = ref(null);
+
+ // 鎶ュ伐寮圭獥
+ const reportDialogVisible = ref(false);
+ const reportForm = reactive({
+ planQuantity: 0,
+ quantity: 0,
+ userName: "",
+ workOrderId: "",
+ reportWork: "",
+ productProcessRouteItemId: "",
+ userId: "",
+ productMainId: null,
+ scrapQty: 0,
+ });
+ const currentReportRowData = ref(null);
+
+ // 鏃ユ湡閫夋嫨鍣�
+ const showDate = ref(false);
+ const currentDateField = ref("");
+
+ // 鐝粍閫夋嫨
+ const showUserSheet = ref(false);
+ const userOptions = ref([]);
+ const userSheetOptions = computed(() => {
+ return userOptions.value.map(user => ({
+ name: user.nickName,
+ value: user.userId,
+ }));
+ });
+
+ // 鏍煎紡鍖栨棩鏈�
+ const formatDate = dateStr => {
+ if (!dateStr) return "-";
+ return dayjs(dateStr).format("YYYY-MM-DD");
+ };
+
+ // 杩涘害鐧惧垎姣旇浆鎹�
+ 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 getWorkOrderTypeTag = type => {
+ switch (type) {
+ case "鐢熶骇宸ュ崟":
+ return "success";
+ case "缁翠慨宸ュ崟":
+ return "warning";
+ case "妫�楠屽伐鍗�":
+ return "info";
+ default:
+ return "info";
+ }
+ };
+
+ // 鑾峰彇瀹屾垚鐘舵�佹爣绛�
+ const getCompletionStatusTag = status => {
+ const percentage = toProgressPercentage(status);
+ if (percentage >= 100) return "success";
+ if (percentage >= 50) return "warning";
+ return "error";
+ };
+
+ // 鑾峰彇瀹屾垚鐘舵�佹枃鏈�
+ const getCompletionStatusText = status => {
+ const percentage = toProgressPercentage(status);
+ if (percentage >= 100) return "宸插畬鎴�";
+ return `${percentage}%`;
+ };
+
+ // 鏌ヨ鍒楄〃
+ const handleQuery = () => {
+ page.current = -1;
+ getList();
+ };
+
+ const getList = () => {
+ tableLoading.value = true;
+ const params = { ...searchForm.value, ...page };
+ productWorkOrderPage(params)
+ .then(res => {
+ tableLoading.value = false;
+ tableData.value = res.data.records || [];
+ // tableData.value = [
+ // {
+ // id: "WO20260304001",
+ // workOrderNo: "WO20260304001",
+ // workOrderType: "鐢熶骇宸ュ崟",
+ // productName: "涓嶉攬閽㈡澘鏉�",
+ // model: "304-2B",
+ // unit: "kg",
+ // processName: "鍒囧壊宸ュ簭",
+ // planQuantity: 1000,
+ // completeQuantity: 650,
+ // completionStatus: 65,
+ // planStartTime: "2026-03-01",
+ // planEndTime: "2026-03-10",
+ // actualStartTime: "2026-03-02",
+ // actualEndTime: null,
+ // remark: "绱ф�ヨ鍗曪紝璇蜂紭鍏堝鐞�",
+ // },
+ // ];
+ page.total = res.data.total || 0;
+ })
+ .catch(() => {
+ tableLoading.value = false;
+ showToast("鑾峰彇宸ュ崟鍒楄〃澶辫触");
+ });
+ };
+
+ // 缂栬緫宸ュ崟
+ const handleEdit = row => {
+ editrow.value = JSON.parse(JSON.stringify(row));
+ editDialogVisible.value = true;
+ };
+
+ // 鏇存柊宸ュ崟
+ const handleUpdate = () => {
+ updateProductWorkOrder(editrow.value)
+ .then(res => {
+ showToast("淇敼鎴愬姛");
+ editDialogVisible.value = false;
+ getList();
+ })
+ .catch(() => {
+ showToast("淇敼澶辫触");
+ });
+ };
+
+ // 鏄剧ず鏃ユ湡閫夋嫨鍣�
+ const showDatePicker = (field, defaultValue) => {
+ currentDateField.value = field;
+ // 璁剧疆榛樿鍊�
+ if (defaultValue) {
+ value1.value = dayjs(defaultValue);
+ } else {
+ value1.value = dayjs();
+ }
+ showDate.value = true;
+ };
+
+ // 纭鏃ユ湡閫夋嫨
+ const confirmDate = e => {
+ if (currentDateField.value && editrow.value) {
+ // 纭繚鏃ユ湡鏍煎紡涓� YYYY-MM-DD
+ const formattedDate = dayjs(e.value).format("YYYY-MM-DD");
+ editrow.value[currentDateField.value] = formattedDate;
+ }
+ showDate.value = false;
+ };
+
+ // 鏄剧ず鎶ュ伐寮圭獥
+ const showReportDialog = row => {
+ currentReportRowData.value = row;
+ reportForm.planQuantity = row.planQuantity || 0;
+ reportForm.quantity = row.quantity || 0;
+ reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
+ reportForm.workOrderId = row.id;
+ reportForm.reportWork = row.reportWork;
+ reportForm.productMainId = row.productMainId;
+ reportForm.scrapQty = row.scrapQty || 0;
+
+ // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
+ getUserProfile()
+ .then(res => {
+ if (res.code === 200) {
+ reportForm.userId = res.data.userId;
+ reportForm.userName = res.data.nickName;
+ }
+ })
+ .catch(err => {
+ console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+ });
+
+ reportDialogVisible.value = true;
+ };
+
+ // 澶勭悊鎶ュ伐
+ const handleReport = () => {
+ if (reportForm.planQuantity <= 0) {
+ showToast("寰呯敓浜ф暟閲忎负0锛屾棤娉曟姤宸�");
+ return;
+ }
+ if (!reportForm.quantity || reportForm.quantity <= 0) {
+ showToast("璇疯緭鍏ユ湁鏁堢殑鏈鐢熶骇鏁伴噺");
+ return;
+ }
+ if (reportForm.quantity > reportForm.planQuantity) {
+ showToast("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�");
+ return;
+ }
+
+ addProductMain(reportForm)
+ .then(res => {
+ if (res.code === 200) {
+ showToast("鎶ュ伐鎴愬姛");
+ reportDialogVisible.value = false;
+ getList();
+ } else {
+ showToast(res.msg || "鎶ュ伐澶辫触");
+ }
+ })
+ .catch(() => {
+ showToast("鎶ュ伐澶辫触");
+ });
+ };
+
+ const viewFileList = item => {
+ uni.setStorageSync("workOrderFileId", item.id);
+ uni.navigateTo({
+ url: "/pages/productionManagement/workOrder/fileList",
+ });
+ };
+
+ // 鑾峰彇鐢ㄦ埛鍒楄〃
+ const getUserList = () => {
+ userListNoPageByTenantId()
+ .then(res => {
+ if (res.code === 200) {
+ userOptions.value = res.data || [];
+ }
+ })
+ .catch(err => {
+ console.error("鑾峰彇鐢ㄦ埛鍒楄〃澶辫触", err);
+ });
+ };
+
+ // 閫夋嫨鐢ㄦ埛
+ const selectUser = e => {
+ reportForm.userId = e.value;
+ const selectedUser = userOptions.value.find(user => user.userId === e.value);
+ if (selectedUser) {
+ reportForm.userName = selectedUser.nickName;
+ }
+ showUserSheet.value = false;
+ };
+
+ onMounted(() => {
+ getList();
+ getUserList();
+ });
+
+ onShow(() => {
+ getList();
+ });
+</script>
+
+<style scoped lang="scss">
+ @import "../../../styles/sales-common.scss";
+
+ .work-order-page {
+ min-height: 100vh;
+ background-color: #f5f5f5;
+ }
+
+ // 鎼滅储鍖哄煙
+ .search-container {
+ padding: 16px;
+ background-color: #ffffff;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
+ }
+
+ .search-box {
+ display: flex;
+ gap: 12px;
+ align-items: center;
+ }
+
+ .search-box :deep(.up-input) {
+ flex: 1;
+ }
+
+ // 宸ュ崟鍒楄〃
+ .work-order-list {
+ padding: 16px;
+ }
+
+ .work-order-item {
+ background: #ffffff;
+ border-radius: 12px;
+ margin-bottom: 16px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
+ overflow: hidden;
+ }
+
+ .item-header {
+ padding: 16px;
+ border-bottom: 1px solid #f0f0f0;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .item-title {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .work-order-no {
+ font-size: 16px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .type-tag {
+ margin-left: 8px;
+ }
+
+ .item-content {
+ padding: 16px;
+ }
+
+ .content-row {
+ display: flex;
+ margin-bottom: 12px;
+ align-items: flex-start;
+ }
+
+ .content-row:last-child {
+ margin-bottom: 0;
+ }
+
+ .label {
+ width: 90px;
+ font-size: 14px;
+ color: #606266;
+ }
+
+ .value {
+ flex: 1;
+ font-size: 14px;
+ color: #303133;
+ }
+
+ .progress-container {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ }
+
+ .progress-bar {
+ flex: 1;
+ }
+
+ .progress-text {
+ font-size: 12px;
+ color: #606266;
+ min-width: 40px;
+ }
+
+ .item-footer {
+ padding: 16px;
+ border-top: 1px solid #f0f0f0;
+ display: flex;
+ gap: 12px;
+ justify-content: flex-end;
+ }
+
+ // 绌虹姸鎬�
+ .no-data {
+ padding: 60px 20px;
+ text-align: center;
+ }
+
+ // 鍒嗛〉缁勪欢
+ .pagination {
+ padding: 20px;
+ background: #fff;
+ margin-top: 10px;
+ display: flex;
+ justify-content: center;
+ }
+
+ // 寮圭獥鏍峰紡
+ .dialog-content {
+ padding: 24px;
+ background: #ffffff;
+ border-radius: 12px;
+ width: 90vw;
+ }
+
+ .dialog-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 24px;
+ padding-bottom: 16px;
+ border-bottom: 1px solid #f0f0f0;
+ }
+
+ .dialog-title {
+ font-size: 18px;
+ font-weight: 600;
+ color: #303133;
+ }
+
+ .dialog-body {
+ margin-bottom: 24px;
+ }
+
+ .form-item {
+ margin-bottom: 20px;
+ }
+
+ .form-label {
+ display: block;
+ font-size: 14px;
+ color: #606266;
+ margin-bottom: 8px;
+ }
+
+ .form-label.required::before {
+ content: "*";
+ color: #f56c6c;
+ margin-right: 4px;
+ }
+
+ .dialog-body :deep(.up-input) {
+ width: 100%;
+ }
+
+ .fake-input-wrapper {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ height: 44px;
+ padding: 0 12px;
+ // background-color: #f5f7fa;
+ border: 1px solid #dcdfe6;
+ border-radius: 4px;
+ }
+
+ .fake-input-text {
+ font-size: 14px;
+ color: #303133;
+ }
+
+ .fake-input-text.placeholder {
+ color: #c0c4cc;
+ }
+
+ .dialog-footer {
+ display: flex;
+ gap: 16px;
+ padding-top: 16px;
+ border-top: 1px solid #f0f0f0;
+ }
+
+ .footer-btn {
+ flex: 1;
+ height: 44px;
+ }
+</style>
\ No newline at end of file
--
Gitblit v1.9.3