From df76c64ca6a49dbff88ea972a68a02ce53ffdbe3 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 04 六月 2026 16:59:17 +0800
Subject: [PATCH] 指标绑定选择产品时,加上工序选择框(过程检、出厂检),支持多选。出厂检验及指标维护给出厂检增加工序字段
---
src/views/productionManagement/workOrder/index.vue | 1505 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 files changed, 1,372 insertions(+), 133 deletions(-)
diff --git a/src/views/productionManagement/workOrder/index.vue b/src/views/productionManagement/workOrder/index.vue
index 291ca18..9c62a41 100644
--- a/src/views/productionManagement/workOrder/index.vue
+++ b/src/views/productionManagement/workOrder/index.vue
@@ -13,7 +13,8 @@
</div>
<div class="search-item">
<el-button type="primary"
- @click="handleQuery">鎼滅储</el-button>
+ @click="handleQuery">鎼滅储
+ </el-button>
</div>
</div>
</div>
@@ -24,10 +25,12 @@
:page="page"
:tableLoading="tableLoading"
@pagination="pagination">
- <template #completionStatus="{ row }">
- <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
- </template>
- </PIMTable>
+ <template #completionStatus="{ row }">
+ <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+ :color="progressColor(toProgressPercentage(row?.completionStatus))"
+ :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+ </template>
+ </PIMTable>
</div>
<el-dialog v-model="editDialogVisible"
title="缂栬緫鏃堕棿"
@@ -36,30 +39,34 @@
label-width="120px">
<el-form-item label="璁″垝寮�濮嬫椂闂�">
<el-date-picker v-model="editrow.planStartTime"
- type="date"
+ type="datetime"
placeholder="璇烽�夋嫨"
- value-format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD HH:mm"
+ format="YYYY-MM-DD HH:mm"
style="width: 300px" />
</el-form-item>
<el-form-item label="璁″垝缁撴潫鏃堕棿">
<el-date-picker v-model="editrow.planEndTime"
- type="date"
+ type="datetime"
placeholder="璇烽�夋嫨"
- value-format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD HH:mm"
+ format="YYYY-MM-DD HH:mm"
style="width: 300px" />
</el-form-item>
<el-form-item label="瀹為檯寮�濮嬫椂闂�">
<el-date-picker v-model="editrow.actualStartTime"
- type="date"
+ type="datetime"
placeholder="璇烽�夋嫨"
- value-format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD HH:mm"
+ format="YYYY-MM-DD HH:mm"
style="width: 300px" />
</el-form-item>
<el-form-item label="瀹為檯缁撴潫鏃堕棿">
<el-date-picker v-model="editrow.actualEndTime"
- type="date"
+ type="datetime"
placeholder="璇烽�夋嫨"
- value-format="YYYY-MM-DD"
+ value-format="YYYY-MM-DD HH:mm"
+ format="YYYY-MM-DD HH:mm"
style="width: 300px" />
</el-form-item>
</el-form>
@@ -96,15 +103,14 @@
</div>
<!-- <div class="info-item">
<span class="info-label">宸ュ崟鐘舵��</span>
- <span class="info-value">{{
- transferCardRowData.status === 1 ? '寰呯‘璁�' :
- transferCardRowData.status === 2 ? '寰呯敓浜�' :
- transferCardRowData.status === 3 ? '鐢熶骇涓�' :
- transferCardRowData.status === 4 ? '宸茬敓浜�' :
- transferCardRowData.status
+ <span class="info-value">{{
+ transferCardRowData.status === 1 ? '寰呯‘璁�' :
+ transferCardRowData.status === 2 ? '寰呯敓浜�' :
+ transferCardRowData.status === 3 ? '鐢熶骇涓�' :
+ transferCardRowData.status === 4 ? '宸茬敓浜�' :
+ transferCardRowData.status
}}</span>
</div> -->
-
<div class="info-item">
<span class="info-label">璁″垝寮�濮嬫椂闂�</span>
<span class="info-value">{{ transferCardRowData.planStartTime }}</span>
@@ -160,46 +166,128 @@
margin-bottom: 40px;">
<el-button type="primary"
style="margin-top: 20px;"
- @click="printTransferCard">鎵撳嵃娴佽浆鍗�</el-button>
+ @click="printTransferCard">鎵撳嵃娴佽浆鍗�
+ </el-button>
</div>
</el-dialog>
<el-dialog v-model="reportDialogVisible"
- title="鎶ュ伐"
- width="500px">
- <el-form :model="reportForm"
+ :title="`鎶ュ伐(宸ュ崟缂栧彿:${currentReportRowData?.workOrderNo || '-'})`"
+ width="1000px">
+ <el-form ref="reportFormRef"
+ :model="reportForm"
+ :rules="reportFormRules"
label-width="120px">
- <el-form-item label="寰呯敓浜ф暟閲�">
- <el-input v-model="reportForm.planQuantity"
- readonly
- style="width: 300px" />
- </el-form-item>
- <el-form-item label="鏈鐢熶骇鏁伴噺">
- <el-input v-model.number="reportForm.quantity"
- type="number"
- min="1"
- style="width: 300px"
- placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�" />
- </el-form-item>
- <el-form-item label="鎶ュ簾鏁伴噺">
- <el-input v-model.number="reportForm.scrapQty"
- type="number"
- min="1"
- style="width: 300px"
- placeholder="璇疯緭鍏ユ姤搴熸暟閲�" />
- </el-form-item>
- <el-form-item label="鐝粍淇℃伅">
- <el-select v-model="reportForm.userId"
- style="width: 300px"
- placeholder="璇烽�夋嫨鐝粍淇℃伅"
- clearable
- filterable
- @change="handleUserChange">
- <el-option v-for="user in userOptions"
- :key="user.userId"
- :label="user.userName"
- :value="user.userId" />
- </el-select>
- </el-form-item>
+ <el-row :gutter="20">
+ <el-col :span="12">
+ <el-form-item label="寰呯敓浜ф暟閲�">
+ <el-input v-model="reportForm.planQuantity"
+ readonly
+ disabled />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鏈鐢熶骇鏁伴噺"
+ prop="quantity">
+ <el-input v-model.number="reportForm.quantity"
+ type="number"
+ min="1"
+ step="1"
+ placeholder="璇疯緭鍏ユ湰娆$敓浜ф暟閲�"
+ style="width: 100%"
+ :class="{ 'over-limit': reportForm.quantity > reportForm.planQuantity }"
+ @input="handleQuantityInput" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="琛ヤ骇鏁伴噺"
+ prop="replenishQty">
+ <el-input v-model.number="reportForm.replenishQty"
+ type="number"
+ min="0"
+ step="1"
+ placeholder="璇疯緭鍏ヨˉ浜ф暟閲�" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鎶ュ簾鏁伴噺"
+ prop="scrapQty">
+ <el-input v-model.number="reportForm.scrapQty"
+ type="number"
+ min="0"
+ step="1"
+ placeholder="璇疯緭鍏ユ姤搴熸暟閲�"
+ @input="handleScrapQtyInput" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鍔犳斁鏁�"
+ prop="addQty">
+ <el-input v-model.number="reportForm.addQty"
+ type="number"
+ min="0"
+ step="1"
+ placeholder="璇疯緭鍏ュ姞鏀炬暟" />
+ </el-form-item>
+ </el-col>
+ <el-col :span="12">
+ <el-form-item label="鐝粍淇℃伅"
+ prop="teamList">
+ <el-select v-model="reportForm.teamList"
+ ref="teamSelectRef"
+ multiple
+ filterable
+ allow-create
+ default-first-option
+ clearable
+ collapse-tags
+ value-key="userName"
+ placeholder="璇烽�夋嫨鎴栬緭鍏ョ彮缁勬垚鍛�"
+ @change="handleTeamListChange">
+ <el-option v-for="user in teamSelectOptions"
+ :key="user.userId || `custom-${user.nickName}`"
+ :label="user.nickName"
+ :value="{ userId: user.userId, userName: user.nickName }" />
+ </el-select>
+ </el-form-item>
+ </el-col>
+ <!-- <el-col :span="12">-->
+ <!-- <el-form-item label="鏈哄彴" prop="deviceId">-->
+ <!-- <el-select-->
+ <!-- v-model="reportForm.deviceId"-->
+ <!-- placeholder="璇烽�夋嫨鏈哄彴"-->
+ <!-- filterable-->
+ <!-- clearable-->
+ <!-- @change="(val) => handleDeviceChange(val)"-->
+ <!-- :disabled="isDetail"-->
+ <!-- >-->
+ <!-- <el-option-->
+ <!-- v-for="item in deviceOptions"-->
+ <!-- :key="item.id"-->
+ <!-- :label="item.deviceName"-->
+ <!-- :value="item.id"-->
+ <!-- />-->
+ <!-- </el-select>-->
+ <!-- </el-form-item>-->
+ <!-- </el-col>-->
+ <!-- <el-col :span="12">-->
+ <!-- <el-form-item label="瀹℃牳浜�" prop="auditUserId">-->
+ <!-- <el-select-->
+ <!-- v-model="reportForm.auditUserId"-->
+ <!-- placeholder="璇烽�夋嫨瀹℃牳浜�"-->
+ <!-- clearable-->
+ <!-- filterable-->
+ <!-- @change="handleReviewerIdChange"-->
+ <!-- >-->
+ <!-- <el-option-->
+ <!-- v-for="user in userOptions"-->
+ <!-- :key="user.userId"-->
+ <!-- :label="user.nickName"-->
+ <!-- :value="user.userId"-->
+ <!-- />-->
+ <!-- </el-select>-->
+ <!-- </el-form-item>-->
+ <!-- </el-col>-->
+ </el-row>
</el-form>
<template #footer>
<span class="dialog-footer">
@@ -209,27 +297,744 @@
</span>
</template>
</el-dialog>
+ <el-dialog v-model="auditDialogVisible"
+ title="瀹℃牳"
+ width="1000px"
+ :close-on-click-modal="false">
+ <el-table :data="auditTableData"
+ border
+ style="width: 100%"
+ v-loading="auditLoading">
+ <el-table-column label="浜у搧鍚嶇О"
+ prop="productName"
+ min-width="140"
+ show-overflow-tooltip />
+ <el-table-column label="瑙勬牸"
+ prop="model"
+ min-width="120"
+ show-overflow-tooltip />
+ <el-table-column label="鍗曚綅"
+ prop="unit"
+ width="80" />
+ <el-table-column label="宸ュ簭鍚嶇О"
+ prop="processName"
+ min-width="120"
+ show-overflow-tooltip />
+ <el-table-column label="闇�姹傛暟閲�"
+ prop="planQuantity"
+ width="110" />
+ <el-table-column label="瀹屾垚鏁伴噺"
+ prop="completeQuantity"
+ width="110" />
+ <el-table-column label="瀹屾垚杩涘害"
+ prop="completionStatus"
+ width="140">
+ <template #default="{ row }">
+ <el-progress :percentage="toProgressPercentage(row?.completionStatus)"
+ :color="progressColor(toProgressPercentage(row?.completionStatus))"
+ :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" />
+ </template>
+ </el-table-column>
+ <el-table-column label="璁″垝寮�濮嬫椂闂�"
+ prop="planStartTime"
+ width="140" />
+ <el-table-column label="璁″垝缁撴潫鏃堕棿"
+ prop="planEndTime"
+ width="140" />
+ </el-table>
+ <template #footer>
+ <span class="dialog-footer">
+ <el-button type="primary"
+ :loading="auditLoading"
+ @click="submitAudit(1)">閫氳繃</el-button>
+ <el-button type="danger"
+ :loading="auditLoading"
+ @click="submitAudit(2)">涓嶉�氳繃</el-button>
+ <el-button :disabled="auditLoading"
+ @click="auditDialogVisible = false">鍙栨秷</el-button>
+ </span>
+ </template>
+ </el-dialog>
+ <el-dialog v-model="scheduleDialogVisible"
+ :title="scheduleDialogTitle"
+ width="1000px"
+ :close-on-click-modal="false">
+ <div class="schedule-panel">
+ <el-row v-if="!isScheduleHistoryMode"
+ style="margin-bottom: 12px;">
+ <el-col>
+ <el-button type="primary"
+ plain
+ :disabled="scheduleLoading || scheduleSaving"
+ @click="addScheduleRow">
+ 鏂板涓�琛�
+ </el-button>
+ </el-col>
+ </el-row>
+ <el-table :data="scheduleRows"
+ border
+ style="width: 100%"
+ v-loading="scheduleLoading">
+ <el-table-column type="index"
+ label="搴忓彿"
+ width="70"
+ align="center"
+ :index="indexMethod" />
+ <el-table-column label="鏈涓婃満鏈哄彴"
+ min-width="220">
+ <template #default="{ row }">
+ <el-select v-model="row.deviceId"
+ placeholder="璇烽�夋嫨鏈哄彴"
+ filterable
+ clearable
+ style="width: 100%"
+ :disabled="scheduleSaving || isScheduleHistoryMode"
+ @change="val => handleScheduleDeviceChange(val, row)">
+ <el-option v-for="item in deviceOptions"
+ :key="item.id"
+ :label="item.deviceName"
+ :value="String(item.id)" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏈涓婃満浜�"
+ min-width="220">
+ <template #default="{ row }">
+ <div v-if="isScheduleHistoryMode"
+ class="schedule-user-tags">
+ <el-tag v-for="(userId, index) in row.userIds"
+ :key="`${userId}-${index}`"
+ type="primary">
+ {{ resolveScheduleUserName(userId) }}
+ </el-tag>
+ <span v-if="!row.userIds?.length">-</span>
+ </div>
+ <el-select v-else
+ v-model="row.userIds"
+ placeholder="璇烽�夋嫨涓婃満浜�"
+ filterable
+ multiple
+ clearable
+ collapse-tags
+ style="width: 100%"
+ :disabled="scheduleSaving"
+ @change="val => handleScheduleUserChange(val, row)">
+ <el-option v-for="user in row.userOptions"
+ :key="user.userId"
+ :label="user.nickName"
+ :value="String(user.userId)" />
+ </el-select>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏈涓婃満鏃堕棿"
+ min-width="240">
+ <template #default="{ row }">
+ <el-date-picker v-model="row.startTime"
+ type="datetime"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ format="YYYY-MM-DD HH:mm:ss"
+ placeholder="璇烽�夋嫨涓婃満鏃堕棿"
+ style="width: 100%"
+ :disabled="scheduleSaving || isScheduleHistoryMode" />
+ </template>
+ </el-table-column>
+ <el-table-column v-if="!isScheduleHistoryMode"
+ label="鎿嶄綔"
+ width="110"
+ align="center">
+ <template #default="{ row }">
+ <el-button link
+ type="danger"
+ :loading="row.deleting"
+ :disabled="scheduleSaving"
+ @click="removeScheduleRow(row)">
+ 鍒犻櫎
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ <Pagination v-show="isScheduleHistoryMode && schedulePage.total > 0"
+ style="margin-top: 12px"
+ :total="schedulePage.total"
+ :page="schedulePage.current"
+ :limit="schedulePage.size"
+ @pagination="handleSchedulePagination" />
+ </div>
+ <template #footer>
+ <span class="dialog-footer">
+ <template v-if="isScheduleHistoryMode">
+ <el-button @click="scheduleDialogVisible = false">鍏抽棴</el-button>
+ </template>
+ <template v-else>
+ <el-button type="primary"
+ :loading="scheduleSaving"
+ @click="handleSaveSchedule">淇濆瓨鎺掍骇</el-button>
+ <el-button :disabled="scheduleSaving"
+ @click="scheduleDialogVisible = false">鍙栨秷</el-button>
+ </template>
+ </span>
+ </template>
+ </el-dialog>
<FilesDia ref="workOrderFilesRef" />
</div>
</template>
<script setup>
- import { onMounted, ref } from "vue";
- import { ElMessageBox } from "element-plus";
+ import { onMounted, ref, nextTick, computed } from "vue";
+ import { deepClone } from "@/utils/index.js";
+ import { ElMessageBox, ElMessage } from "element-plus";
+ import Pagination from "@/components/PIMTable/Pagination.vue";
import dayjs from "dayjs";
+ import { processList } from "@/api/productionManagement/productionProcess.js";
import {
productWorkOrderPage,
updateProductWorkOrder,
addProductMain,
downProductWorkOrder,
+ addProductionMachineRecord,
+ productionMachineRecordListPage,
+ deleteProductionMachineRecord,
} from "@/api/productionManagement/workOrder.js";
import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js";
import QRCode from "qrcode";
import { getCurrentInstance, reactive, toRefs } from "vue";
import FilesDia from "./components/filesDia.vue";
+ import { getDeviceLedger } from "@/api/equipmentManagement/ledger.js";
+
const { proxy } = getCurrentInstance();
+ const currentUserId = ref("");
+ const deviceOptions = ref([]);
+ const currentUserName = ref("");
+ const teamSelectRef = ref(null);
+
+ const ensureCurrentUser = async () => {
+ if (currentUserId.value) return;
+ try {
+ const res = await getUserProfile();
+ if (res?.code === 200) {
+ currentUserId.value = String(res?.data?.userId ?? "");
+ currentUserName.value = String(res?.data?.nickName ?? "");
+ }
+ } catch (err) {
+ console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
+ }
+ };
+
+ // 鏈哄彴鑾峰彇
+ const getDeviceList = () => {
+ getDeviceLedger().then(res => {
+ deviceOptions.value = Array.isArray(res?.data) ? res.data : [];
+ });
+ };
+
+ const handleDeviceChange = val => {
+ const device = deviceOptions.value.find(item => item.id === val);
+ reportForm.deviceName = device?.deviceName || "";
+ reportForm.deviceId = val || "";
+ };
+
+ const normalizeArray = val => {
+ if (val === null || val === undefined) return [];
+ if (Array.isArray(val)) return val;
+ if (typeof val === "string") {
+ return val
+ .split(/[,锛�;锛沑s]+/g)
+ .map(s => s.trim())
+ .filter(Boolean);
+ }
+ return [val];
+ };
+
+ const isCurrentUserInUserIds = row => {
+ const uid = String(currentUserId.value || "");
+ if (!uid) return false;
+
+ const ids = normalizeArray(row?.userIds)
+ .map(id => String(id))
+ .filter(Boolean);
+
+ return ids.includes(uid);
+ };
+
+ // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍦ㄥ伐搴忔姤宸ヤ汉涓�
+ const isCurrentUserInProcessUserIds = row => {
+ const uid = String(currentUserId.value || "");
+ if (!uid) return false;
+
+ const ids = normalizeArray(row?.processUserIds)
+ .map(id => String(id))
+ .filter(Boolean);
+
+ return ids.includes(uid);
+ };
+
+ // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鍙互鎶ュ伐锛堝伐鍗曟姤宸ヤ汉 鎴� 宸ュ簭鎶ュ伐浜猴級
+ const canCurrentUserReport = row => {
+ return isCurrentUserInUserIds(row) || isCurrentUserInProcessUserIds(row);
+ };
+
+ const canOperateByReportWorker = computed(() => {
+ return row => isCurrentUserReportWorker(row);
+ });
+
+ const isRowScheduled = row => {
+ const ids = normalizeArray(row?.userIds)
+ .map(val => String(val))
+ .filter(Boolean);
+ if (!ids.length) return false;
+ return ids.some(val => val !== "0");
+ };
+
+ const buildBaseScheduleUsersByRow = row => {
+ if (!row) return [];
+
+ if (Array.isArray(row?.reportWorkerList) && row.reportWorkerList.length > 0) {
+ const mapped = row.reportWorkerList
+ .map(item => {
+ const userId = String(item?.userId ?? item?.id ?? "").trim();
+ const nickName = String(item?.userName ?? item?.nickName ?? "").trim();
+ return { userId, nickName: nickName || userId };
+ })
+ .filter(item => item.userId);
+ const uniq = new Map();
+ mapped.forEach(item => uniq.set(String(item.userId), item));
+ return Array.from(uniq.values());
+ }
+
+ const configuredIds = [
+ row.reportUserIds,
+ row.reportWorkerIds,
+ row.userIdList,
+ row.reportUserId,
+ row.userId,
+ ]
+ .flatMap(v => normalizeArray(v))
+ .map(v => String(v).trim())
+ .filter(Boolean);
+
+ if (configuredIds.length > 0) {
+ const uniqIds = Array.from(new Set(configuredIds));
+ return uniqIds.map(id => {
+ const user = userTeamOptions.value.find(
+ u => String(u.userId) === String(id)
+ );
+ return { userId: String(id), nickName: user?.nickName || String(id) };
+ });
+ }
+
+ return userTeamOptions.value.map(u => ({
+ userId: String(u.userId),
+ nickName: u.nickName,
+ }));
+ };
+
+ const resolveScheduleUserName = userId => {
+ const uid = String(userId ?? "").trim();
+ if (!uid) return "";
+ const inBase = baseScheduleUsers.value.find(u => String(u.userId) === uid);
+ if (inBase?.nickName) return inBase.nickName;
+ const inTeam = userTeamOptions.value.find(u => String(u.userId) === uid);
+ return inTeam?.nickName || uid;
+ };
+
+ const buildScheduleUserOptionsByDeviceId = deviceId => {
+ const device = deviceOptions.value.find(
+ item => String(item.id) === String(deviceId)
+ );
+
+ const operatorIds = device?.operatorId
+ ? String(device.operatorId)
+ .split(/[,锛�;锛沑s]+/g)
+ .map(id => id.trim())
+ .filter(Boolean)
+ : [];
+
+ if (!operatorIds.length) {
+ return [...baseScheduleUsers.value];
+ }
+
+ return baseScheduleUsers.value.filter(user =>
+ operatorIds.includes(String(user.userId))
+ );
+ };
+
+ const createScheduleRow = (preset = {}) => {
+ const deviceId =
+ preset?.deviceId === null || preset?.deviceId === undefined
+ ? ""
+ : String(preset.deviceId);
+
+ const userOptions = deviceId
+ ? buildScheduleUserOptionsByDeviceId(deviceId)
+ : [...baseScheduleUsers.value];
+
+ const userIds = normalizeArray(preset?.userIds)
+ .map(val => String(val))
+ .filter(Boolean)
+ .filter(uid =>
+ userOptions.some(user => String(user.userId) === String(uid))
+ );
+
+ return {
+ id: preset?.id ?? "",
+ deviceId,
+ deviceName: preset?.deviceName ?? "",
+ userIds,
+ userOptions,
+ startTime: preset?.startTime ?? dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ deleting: false,
+ };
+ };
+
+ const addScheduleRow = preset => {
+ if (preset) {
+ scheduleRows.value.push(createScheduleRow(preset));
+ return;
+ }
+
+ scheduleRows.value.push(
+ createScheduleRow({
+ id: "",
+ deviceId: "",
+ deviceName: "",
+ userIds: [],
+ startTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
+ })
+ );
+ };
+
+ const refreshScheduleRows = async () => {
+ const workOrderRow = currentReportRowData.value;
+
+ if (!workOrderRow?.id) {
+ schedulePage.current = 1;
+ schedulePage.total = 0;
+ scheduleRows.value = [];
+ return;
+ }
+
+ scheduleLoading.value = true;
+ try {
+ const res = await productionMachineRecordListPage({
+ workOrderId: workOrderRow.id,
+ current: schedulePage.current,
+ size: schedulePage.size,
+ });
+
+ const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+ const apiTotal = Number(res?.data?.total);
+ schedulePage.total =
+ Number.isFinite(apiTotal) && apiTotal > 0 ? apiTotal : records.length;
+
+ const lastPage = Math.max(
+ 1,
+ Math.ceil((schedulePage.total || 0) / schedulePage.size)
+ );
+ if (schedulePage.current > lastPage) {
+ schedulePage.current = lastPage;
+ await refreshScheduleRows();
+ return;
+ }
+
+ const rows = records.map(record => mapMachineRecordToScheduleRow(record));
+ scheduleRows.value = rows;
+ } catch (error) {
+ console.error("鑾峰彇鎺掍骇璁板綍澶辫触", error);
+ schedulePage.total = 0;
+ scheduleRows.value = [];
+ ElMessage.error("鑾峰彇鎺掍骇璁板綍澶辫触");
+ } finally {
+ scheduleLoading.value = false;
+ }
+ };
+
+ const removeScheduleRow = async row => {
+ if (!row || isScheduleHistoryMode.value) return;
+
+ if (!row.id) {
+ scheduleRows.value = scheduleRows.value.filter(item => item !== row);
+ if (!scheduleRows.value.length) {
+ addScheduleRow();
+ }
+ return;
+ }
+
+ try {
+ await ElMessageBox.confirm("纭畾鍒犻櫎杩欐潯鎺掍骇璁板綍鍚楋紵", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+ } catch {
+ return;
+ }
+
+ row.deleting = true;
+ try {
+ const res = await deleteProductionMachineRecord([row.id]);
+ if (res?.code !== undefined && res.code !== 200) {
+ ElMessage.error(res?.msg || "鍒犻櫎澶辫触");
+ return;
+ }
+
+ ElMessage.success("鍒犻櫎鎴愬姛");
+ await refreshScheduleRows();
+ getList();
+ } catch (error) {
+ console.error("鍒犻櫎鎺掍骇璁板綍澶辫触", error);
+ ElMessage.error("鍒犻櫎澶辫触锛岃閲嶈瘯");
+ } finally {
+ row.deleting = false;
+ }
+ };
+
+ const handleScheduleUserChange = (userIds, row) => {
+ row.userIds = normalizeArray(userIds)
+ .map(val => String(val))
+ .filter(Boolean);
+ };
+
+ const handleScheduleDeviceChange = (deviceId, row) => {
+ const device = deviceOptions.value.find(
+ item => String(item.id) === String(deviceId)
+ );
+
+ row.deviceId =
+ deviceId === null || deviceId === undefined ? "" : String(deviceId);
+ row.deviceName = device?.deviceName || "";
+ row.userOptions = row.deviceId
+ ? buildScheduleUserOptionsByDeviceId(row.deviceId)
+ : [...baseScheduleUsers.value];
+
+ row.userIds = normalizeArray(row.userIds)
+ .map(uid => String(uid))
+ .filter(uid =>
+ row.userOptions.some(user => String(user.userId) === String(uid))
+ );
+ };
+
+ const handleSchedulePagination = ({ page, limit }) => {
+ if (!isScheduleHistoryMode.value) return;
+ schedulePage.current = page;
+ schedulePage.size = limit;
+ refreshScheduleRows();
+ };
+
+ const validateScheduleRows = () => {
+ if (!scheduleRows.value.length) {
+ ElMessage.warning("璇疯嚦灏戞坊鍔犱竴鏉′笂鏈轰俊鎭�");
+ return false;
+ }
+
+ for (let index = 0; index < scheduleRows.value.length; index += 1) {
+ const row = scheduleRows.value[index];
+
+ if (!row.deviceId) {
+ ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨鏈哄彴`);
+ return false;
+ }
+
+ if (!Array.isArray(row.userIds) || row.userIds.length === 0) {
+ ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨涓婃満浜篳);
+ return false;
+ }
+
+ if (!row.startTime) {
+ ElMessage.warning(`绗�${index + 1}琛岃閫夋嫨涓婃満鏃堕棿`);
+ return false;
+ }
+
+ if (!dayjs(row.startTime).isValid()) {
+ ElMessage.warning(`绗�${index + 1}琛屼笂鏈烘椂闂存牸寮忎笉姝g‘`);
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ const buildMachineRecordPayload = (
+ workOrderRow,
+ scheduleRow,
+ sortIndex = 0
+ ) => {
+ const processId =
+ workOrderRow?.processId ??
+ workOrderRow?.productProcessRouteItemId ??
+ reportForm.productProcessRouteItemId;
+
+ const operatorIds = normalizeArray(scheduleRow?.userIds)
+ .map(val => String(val).trim())
+ .filter(Boolean)
+ .join(",");
+
+ const nickName = normalizeArray(scheduleRow?.userIds)
+ .map(uid => resolveScheduleUserName(uid))
+ .filter(Boolean)
+ .join(",");
+
+ const payload = {
+ workOrderId: workOrderRow?.id,
+ processId,
+ machineId: scheduleRow.deviceId ? Number(scheduleRow.deviceId) : undefined,
+ deviceName: scheduleRow.deviceName,
+ operatorId: operatorIds || undefined,
+ nickName: nickName || "",
+ machineStartTime: scheduleRow.startTime,
+ reportStatus: false,
+ remark: `鎺掍骇搴忓彿:${sortIndex + 1}`,
+ };
+
+ if (scheduleRow.id) {
+ payload.id = scheduleRow.id;
+ }
+
+ return payload;
+ };
+
+ const indexMethod = index => {
+ return (schedulePage.current - 1) * schedulePage.size + index + 1;
+ };
+
+ const scheduleDialogMode = ref("create");
+ const isScheduleHistoryMode = computed(
+ () => scheduleDialogMode.value === "history"
+ );
+ const scheduleDialogTitle = computed(
+ () =>
+ `${isScheduleHistoryMode.value ? "鎺掍骇璁板綍" : "鐢熶骇鎺掍骇"}(宸ュ崟缂栧彿:${
+ currentReportRowData.value?.workOrderNo || "-"
+ })`
+ );
+
+ const mapMachineRecordToScheduleRow = record => {
+ const id = record?.id ?? "";
+ const deviceId = record?.machineId ?? record?.deviceId ?? "";
+ const deviceName = record?.deviceName ?? record?.machineName ?? "";
+ const startTime = record?.machineStartTime ?? record?.startTime ?? "";
+ const userIds = normalizeArray(
+ record?.operatorId ?? record?.operatorIds ?? record?.userId
+ )
+ .map(val => String(val))
+ .filter(Boolean);
+
+ return createScheduleRow({
+ id,
+ deviceId:
+ deviceId === null || deviceId === undefined ? "" : String(deviceId),
+ deviceName,
+ userIds,
+ startTime,
+ });
+ };
+
+ const buildScheduleRowsFromRecords = records => {
+ const list = Array.isArray(records) ? records : [];
+ const grouped = new Map();
+
+ list.forEach(record => {
+ const row = mapMachineRecordToScheduleRow(record);
+ const key = `${row.deviceId}__${row.startTime}__${row.deviceName}`;
+
+ if (!grouped.has(key)) {
+ grouped.set(key, row);
+ return;
+ }
+
+ const existing = grouped.get(key);
+ existing.ids = Array.from(new Set([existing.id, row.id].filter(Boolean)));
+ existing.userIds = Array.from(
+ new Set(
+ [...(existing?.userIds || []), ...(row?.userIds || [])].map(v =>
+ String(v)
+ )
+ )
+ ).filter(Boolean);
+
+ if (!existing.deviceName && row.deviceName)
+ existing.deviceName = row.deviceName;
+ });
+
+ return Array.from(grouped.values()).sort(
+ (a, b) => dayjs(a.startTime).valueOf() - dayjs(b.startTime).valueOf()
+ );
+ };
+
+ const resetCreateScheduleRows = () => {
+ schedulePage.current = 1;
+ schedulePage.total = 0;
+ scheduleRows.value = [];
+ addScheduleRow();
+ };
+
+ const openScheduleDialog = async row => {
+ scheduleDialogMode.value = "create";
+ currentReportRowData.value = row;
+ baseScheduleUsers.value = buildBaseScheduleUsersByRow(row);
+ userTemp.value = [...baseScheduleUsers.value];
+ scheduleDialogVisible.value = true;
+ resetCreateScheduleRows();
+ };
+
+ const openHistoryTimelineDialog = async row => {
+ scheduleDialogMode.value = "history";
+ currentReportRowData.value = row;
+ baseScheduleUsers.value = buildBaseScheduleUsersByRow(row);
+ userTemp.value = [...baseScheduleUsers.value];
+ schedulePage.current = 1;
+ schedulePage.total = 0;
+ scheduleRows.value = [];
+ scheduleDialogVisible.value = true;
+
+ await refreshScheduleRows();
+ };
+
+ const handleSaveSchedule = async () => {
+ if (isScheduleHistoryMode.value) return;
+ if (scheduleSaving.value) return;
+ if (!validateScheduleRows()) return;
+
+ const workOrderRow = currentReportRowData.value;
+ if (!workOrderRow?.id) {
+ ElMessage.warning("缂哄皯宸ュ崟淇℃伅锛屾棤娉曚繚瀛樻帓浜�");
+ return;
+ }
+
+ const sortedRows = [...scheduleRows.value].sort(
+ (a, b) => dayjs(a.startTime).valueOf() - dayjs(b.startTime).valueOf()
+ );
+
+ scheduleSaving.value = true;
+ try {
+ const productionMachineRecord = sortedRows.map((scheduleRow, index) =>
+ buildMachineRecordPayload(workOrderRow, scheduleRow, index)
+ );
+
+ const res = await addProductionMachineRecord({ productionMachineRecord });
+ if (res?.code !== undefined && res.code !== 200) {
+ ElMessage.error(res?.msg || "淇濆瓨鎺掍骇澶辫触");
+ return;
+ }
+
+ proxy.$modal.msgSuccess("鎺掍骇宸蹭繚瀛�");
+ scheduleDialogVisible.value = false;
+ resetCreateScheduleRows();
+ await getList();
+ } catch (error) {
+ console.error("淇濆瓨鎺掍骇澶辫触", error);
+ ElMessage.error("淇濆瓨鎺掍骇澶辫触锛岃閲嶈瘯");
+ } finally {
+ scheduleSaving.value = false;
+ }
+ };
+
const tableColumn = ref([
+ {
+ label: "宸ュ崟绫诲瀷",
+ prop: "workOrderType",
+ width: "80",
+ },
{
label: "宸ュ崟缂栧彿",
prop: "workOrderNo",
@@ -239,20 +1044,27 @@
label: "鐢熶骇璁㈠崟鍙�",
prop: "productOrderNpsNo",
width: "140",
+ formatData: val => (val && val.length > 4 ? val.slice(0, -4) : val || ""),
},
{
- label: "浜у搧鍚嶇О",
- prop: "productName",
- width: "140",
+ label: "鎴愬搧鍚嶇О",
+ prop: "finalProductModel",
+ minWidth: 200,
+ overHidden: false,
},
- {
- label: "瑙勬牸",
- prop: "model",
- },
- {
- label: "鍗曚綅",
- prop: "unit",
- },
+ // {
+ // label: "鍔犲伐鍝佸悕绉�",
+ // prop: "productName",
+ // width: "140",
+ // },
+ // {
+ // label: "鍔犲伐鍝佽鏍�",
+ // prop: "model",
+ // },
+ // {
+ // label: "鍔犲伐鍝佸崟浣�",
+ // prop: "unit",
+ // },
{
label: "宸ュ簭鍚嶇О",
prop: "processName",
@@ -296,7 +1108,7 @@
},
{
label: "鎿嶄綔",
- width: "200",
+ width: "220",
align: "center",
dataType: "action",
fixed: "right",
@@ -324,33 +1136,265 @@
clickFun: row => {
showReportDialog(row);
},
- disabled: row => row.planQuantity <= 0,
+ // 鐢ㄦ埛褰撳墠id鍦ㄥ伐鍗曟姤宸ヤ汉鎴栧伐搴忔姤宸ヤ汉涓�
+ disabled: row =>
+ row.completeQuantity >= row.planQuantity ||
+ !canCurrentUserReport(row) ||
+ row.hasUnreportedMachine,
},
+ {
+ name: "鐢熶骇鎺掍骇",
+ clickFun: row => {
+ if (!row.canSchedule) {
+ ElMessage.warning("褰撳墠鐢ㄦ埛涓嶅湪璇ュ伐搴忎汉鍛樹腑锛屼笉鑳界敓浜ф帓浜�");
+ return;
+ }
+ openScheduleDialog(row);
+ },
+ disabled: row =>
+ !row.canSchedule || row.completeQuantity >= row.planQuantity,
+ },
+ {
+ name: "鎺掍骇璁板綍",
+ clickFun: row => {
+ if (!row.canSchedule) {
+ ElMessage.warning("褰撳墠鐢ㄦ埛涓嶅湪璇ュ伐搴忎汉鍛樹腑锛屼笉鑳芥煡鐪嬫帓浜ц褰�");
+ return;
+ }
+ openHistoryTimelineDialog(row);
+ },
+ disabled: row => !row.canSchedule,
+ },
+ // {
+ // name:"瀹℃牳",
+ // color: "#f56c6c",
+ // clickFun: row => {
+ // handleAudit(row);
+ // },
+ // disabled: row => Number(row?.auditStatus) === 1,
+ // }
],
},
]);
const tableData = ref([]);
const tableLoading = ref(false);
- const qrCodeUrl = ref("");
- const qrRowData = ref(null);
+ const scheduleRows = ref([]);
+ const scheduleLoading = ref(false);
+ const scheduleSaving = ref(false);
+ const schedulePage = reactive({
+ current: 1,
+ size: 10,
+ total: 0,
+ });
const editDialogVisible = ref(false);
const transferCardVisible = ref(false);
- const transferCardData = ref([]);
const transferCardQrUrl = ref("");
+ const scheduleDialogVisible = ref(false);
const transferCardRowData = ref(null);
+ const baseScheduleUsers = ref([]);
+ const userTemp = ref([]);
const reportDialogVisible = ref(false);
+ const auditDialogVisible = ref(false);
+ const auditRowData = ref(null);
+ const auditTableData = ref([]);
+ const auditLoading = ref(false);
const workOrderFilesRef = ref(null);
+ const reportFormRef = ref(null);
const userOptions = ref([]);
+ const userTeamOptions = ref([]);
const reportForm = reactive({
planQuantity: 0,
- quantity: 0,
+ quantity: null,
+ scrapQty: null,
+ addQty: 0,
+ startTime: "",
+ endTime: "",
userName: "",
workOrderId: "",
reportWork: "",
productProcessRouteItemId: "",
userId: "",
productMainId: null,
+ teamList: [],
+ deviceId: null,
});
+ const teamSelectOptions = computed(() => {
+ const base =
+ Array.isArray(reportForm.userIdsList) && reportForm.userIdsList.length > 0
+ ? reportForm.userIdsList.map(u => ({
+ userId: String(u.userId ?? ""),
+ nickName: String(u.nickName ?? "").trim(),
+ }))
+ : [];
+ const baseNameSet = new Set(base.map(u => u.nickName));
+ const selected = Array.isArray(reportForm.teamList)
+ ? reportForm.teamList
+ : [];
+ const extraNames = selected
+ .map(item => {
+ if (typeof item === "string") return String(item).trim();
+ const name = item?.userName ?? item?.nickName ?? "";
+ return String(name).trim();
+ })
+ .filter(Boolean)
+ .filter(name => !baseNameSet.has(name));
+ const extras = extraNames.map(name => ({ userId: "", nickName: name }));
+ return [...base, ...extras];
+ });
+ function removeLastFour(str) {
+ if (!str) return ""; // 绌哄�间繚鎶�
+ return str.toString().slice(0, -4); // 鏍稿績锛氭埅鍙� 0 鍒� 鍊掓暟绗�4浣�
+ }
+ // 鏈鐢熶骇鏁伴噺楠岃瘉瑙勫垯
+ const validateQuantity = (rule, value, callback) => {
+ if (value === null || value === undefined || value === "") {
+ callback(new Error("璇疯緭鍏ユ湰娆$敓浜ф暟閲�"));
+ return;
+ }
+ const num = Number(value);
+ // 鏁存暟涓斿ぇ浜庣瓑浜�1
+ if (isNaN(num) || !Number.isInteger(num) || num < 1) {
+ callback(new Error("鏈鐢熶骇鏁伴噺蹇呴』澶т簬绛変簬1"));
+ return;
+ }
+ callback();
+ };
+
+ // 鎶ュ簾鏁伴噺楠岃瘉瑙勫垯
+ const validateScrapQty = (rule, value, callback) => {
+ if (value === null || value === undefined || value === "") {
+ callback();
+ return;
+ }
+ const num = Number(value);
+ // 鏁存暟涓斿ぇ浜庣瓑浜�0
+ if (isNaN(num) || !Number.isInteger(num) || num < 0) {
+ callback(new Error("鎶ュ簾鏁伴噺蹇呴』澶т簬绛変簬0"));
+ return;
+ }
+ callback();
+ };
+
+ // 瀹℃牳
+ const handleAudit = row => {
+ if (Number(row?.auditStatus) === 1) {
+ ElMessage.warning("璇ュ伐鍗曞凡瀹℃牳");
+ return;
+ }
+ auditRowData.value = row;
+ const workOrderNo = row?.workOrderNo;
+ const related = workOrderNo
+ ? tableData.value.filter(r => r?.workOrderNo === workOrderNo)
+ : [];
+ auditTableData.value = related.length > 0 ? related : [row];
+ auditDialogVisible.value = true;
+ };
+
+ const submitAudit = async result => {
+ const current = auditRowData.value;
+ if (!current) return;
+ if (auditLoading.value) return;
+
+ const confirmText = result === 1 ? "纭畾瀹℃牳閫氳繃鍚楋紵" : "纭畾瀹℃牳涓嶉�氳繃鍚楋紵";
+ try {
+ await ElMessageBox.confirm(confirmText, "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ cancelButtonText: "鍙栨秷",
+ type: "warning",
+ });
+ } catch {
+ return;
+ }
+
+ auditLoading.value = true;
+ try {
+ const updates = auditTableData.value.map(item => {
+ const id = item?.id;
+ if (!id) return Promise.resolve();
+ return updateProductWorkOrder({ id, auditStatus: result });
+ });
+ await Promise.all(updates);
+ ElMessage.success("瀹℃牳鎴愬姛");
+ auditDialogVisible.value = false;
+ await getList();
+ } finally {
+ auditLoading.value = false;
+ }
+ };
+
+ // 鏌ョ湅璇︽儏
+ const handleView = row => {
+ const { workOrderId } = row;
+ router.push({
+ path: "/productionManagement/workOrderDetail",
+ query: { workOrderId },
+ });
+ };
+
+ // 楠岃瘉瑙勫垯
+ const reportFormRules = {
+ quantity: [{ required: true, validator: validateQuantity, trigger: "blur" }],
+ scrapQty: [{ validator: validateScrapQty, trigger: "blur" }],
+ startTime: [{ required: true, message: "璇烽�夋嫨寮�濮嬫椂闂�", trigger: "change" }],
+ endTime: [{ required: true, message: "璇烽�夋嫨缁撴潫鏃堕棿", trigger: "change" }],
+ // auditUserId: [{required: true, message: "璇烽�夋嫨瀹℃牳浜�", trigger: "change"}],
+ teamList: [{ required: true, message: "璇烽�夋嫨鐝粍", trigger: "change" }],
+ deviceId: [{ required: true, message: "璇烽�夋嫨璁惧", trigger: "change" }],
+ };
+
+ // 澶勭悊鏈鐢熶骇鏁伴噺杈撳叆锛岄檺鍒跺繀椤诲ぇ浜庣瓑浜�1
+ const handleQuantityInput = value => {
+ if (value === "" || value === null || value === undefined) {
+ reportForm.quantity = null;
+ return;
+ }
+ const num = Number(value);
+ if (isNaN(num)) {
+ return;
+ }
+ // 濡傛灉灏忎簬1锛屾竻闄�
+ if (num < 1) {
+ reportForm.quantity = null;
+ return;
+ }
+ // 濡傛灉鏄皬鏁板彇鏁存暟閮ㄥ垎
+ if (!Number.isInteger(num)) {
+ const intValue = Math.floor(num);
+ // 濡傛灉鍙栨暣鍚庡皬浜�1锛屾竻闄�
+ if (intValue < 1) {
+ reportForm.quantity = null;
+ return;
+ }
+ reportForm.quantity = intValue;
+ return;
+ }
+ reportForm.quantity = num;
+ };
+
+ // 澶勭悊鎶ュ簾鏁伴噺
+ const handleScrapQtyInput = value => {
+ if (value === "" || value === null || value === undefined) {
+ reportForm.scrapQty = null;
+ return;
+ }
+ const num = Number(value);
+ // 濡傛灉鏄疦aN锛屼繚鎸佸師鍊�
+ if (isNaN(num)) {
+ return;
+ }
+ // 濡傛灉鏄礋鏁帮紝娓呴櫎杈撳叆
+ if (num < 0) {
+ reportForm.scrapQty = null;
+ return;
+ }
+ // 濡傛灉鏄皬鏁帮紝鍙栨暣鏁伴儴鍒�
+ if (!Number.isInteger(num)) {
+ reportForm.scrapQty = Math.floor(num);
+ return;
+ }
+ // 鏈夋晥鐨勯潪璐熸暣鏁帮紙鍖呮嫭0锛�
+ reportForm.scrapQty = num;
+ };
const currentReportRowData = ref(null);
const page = reactive({
current: 1,
@@ -391,18 +1435,27 @@
page.size = obj.limit;
getList();
};
- const getList = () => {
+ const getList = async () => {
tableLoading.value = true;
- const params = { ...searchForm.value, ...page };
- productWorkOrderPage(params)
- .then(res => {
- tableLoading.value = false;
- tableData.value = res.data.records;
- page.total = res.data.total;
- })
- .catch(() => {
- tableLoading.value = false;
- });
+
+ try {
+ await ensureCurrentUser();
+ await processLists();
+
+ const params = { ...searchForm.value, ...page };
+ const res = await productWorkOrderPage(params);
+
+ const records = Array.isArray(res?.data?.records) ? res.data.records : [];
+
+ tableData.value = records.map(row => ({
+ ...row,
+ canSchedule: canScheduleByWorkOrderNo(row),
+ }));
+
+ page.total = res?.data?.total || 0;
+ } finally {
+ tableLoading.value = false;
+ }
};
// 涓嬭浇骞舵墦鍗板伐鍗曟祦杞崱锛堟枃浠舵祦锛�
@@ -425,7 +1478,9 @@
// 鍒涘缓 Blob URL
const fileBlob =
- blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" });
+ blob instanceof Blob
+ ? blob
+ : new Blob([blob], { type: blob.type || "application/octet-stream" });
const url = window.URL.createObjectURL(fileBlob);
// 鍒涘缓闅愯棌 iframe锛岀敤浜庤Е鍙戞祻瑙堝櫒鎵撳嵃
@@ -468,6 +1523,10 @@
};
const handleEdit = row => {
+ // if (!isCurrentUserReportWorker(row)) {
+ // ElMessage.warning("褰撳墠鐢ㄦ埛涓嶆槸璇ュ伐鍗曠殑鎶ュ伐浜猴紝鏃犳硶缂栬緫");
+ // return;
+ // }
editrow.value = JSON.parse(JSON.stringify(row));
editDialogVisible.value = true;
};
@@ -488,24 +1547,44 @@
const showReportDialog = row => {
currentReportRowData.value = row;
- reportForm.planQuantity = row.planQuantity;
- reportForm.quantity = row.quantity;
+ reportForm.planQuantity = row.planQuantity - row.completeQuantity;
+ reportForm.quantity = row.planQuantity - row.completeQuantity;
reportForm.productProcessRouteItemId = row.productProcessRouteItemId;
reportForm.workOrderId = row.id;
reportForm.reportWork = row.reportWork;
reportForm.productMainId = row.productMainId;
- reportForm.scrapQty = row.scrapQty;
- // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅锛岃缃负榛樿閫変腑
- getUserProfile()
- .then(res => {
- if (res.code === 200) {
- reportForm.userId = res.data.userId;
- reportForm.userName = res.data.userName;
- }
- })
- .catch(err => {
- console.error("鑾峰彇鐢ㄦ埛淇℃伅澶辫触", err);
- });
+ reportForm.startTime = "";
+ reportForm.endTime = "";
+ reportForm.replenishQty = 0;
+ reportForm.teamList = [];
+ reportForm.scrapQty = 0;
+ reportForm.addQty = 0;
+ reportForm.userIds = row.userIds || [];
+
+ // 鍚堝苟宸ュ崟鎶ュ伐浜哄拰宸ュ簭鎶ュ伐浜猴紝鍘婚噸
+ const workOrderUserIds = normalizeArray(row.userIds)
+ .map(id => String(id).trim())
+ .filter(Boolean);
+ const processUserIds = normalizeArray(row.processUserIds)
+ .map(id => String(id).trim())
+ .filter(Boolean);
+ const allowedUserIds = [...new Set([...workOrderUserIds, ...processUserIds])];
+
+ // 鍙厑璁搁�夋嫨宸ュ崟鎶ュ伐浜哄拰宸ュ簭鎶ュ伐浜�
+ reportForm.userIdsList = userTeamOptions.value
+ .filter(item => allowedUserIds.includes(String(item.userId)))
+ .map(item => ({
+ userId: item.userId,
+ nickName: item.nickName,
+ }));
+
+ nextTick(() => {
+ reportFormRef.value?.clearValidate();
+ });
+ ensureCurrentUser().then(() => {
+ reportForm.userId = currentUserId.value;
+ reportForm.userName = currentUserName.value;
+ });
reportDialogVisible.value = true;
};
@@ -515,35 +1594,77 @@
};
const handleReport = () => {
- if (reportForm.planQuantity <= 0) {
- ElMessageBox.alert("寰呯敓浜ф暟閲忎负0锛屾棤娉曟姤宸�", "鎻愮ず", {
- confirmButtonText: "纭畾",
- });
- return;
- }
- if (!reportForm.quantity || reportForm.quantity <= 0) {
- ElMessageBox.alert("璇疯緭鍏ユ湁鏁堢殑鏈鐢熶骇鏁伴噺", "鎻愮ず", {
- confirmButtonText: "纭畾",
- });
- return;
- }
- if (reportForm.quantity > reportForm.planQuantity) {
- ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
- confirmButtonText: "纭畾",
- });
- return;
- }
- // console.log(reportForm);
- addProductMain(reportForm).then(res => {
- if (res.code === 200) {
- proxy.$modal.msgSuccess("鎶ュ伐鎴愬姛");
- reportDialogVisible.value = false;
- getList();
- } else {
- ElMessageBox.alert(res.msg || "鎶ュ伐澶辫触", "鎻愮ず", {
+ reportFormRef.value?.validate(valid => {
+ if (!valid) {
+ return false;
+ }
+
+ if (reportForm.planQuantity <= 0) {
+ ElMessageBox.alert("寰呯敓浜ф暟閲忎负0锛屾棤娉曟姤宸�", "鎻愮ず", {
confirmButtonText: "纭畾",
});
+ return;
}
+
+ // 楠岃瘉鏈鐢熶骇鏁伴噺
+ if (
+ reportForm.quantity === null ||
+ reportForm.quantity === undefined ||
+ reportForm.quantity === ""
+ ) {
+ ElMessageBox.alert("璇疯緭鍏ユ湰娆$敓浜ф暟閲�", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ });
+ return;
+ }
+
+ const quantity = Number(reportForm.quantity);
+ const scrapQty =
+ reportForm.scrapQty === null ||
+ reportForm.scrapQty === undefined ||
+ reportForm.scrapQty === ""
+ ? 0
+ : Number(reportForm.scrapQty);
+
+ // 鏈鐢熶骇鏁伴噺
+ if (isNaN(quantity) || !Number.isInteger(quantity) || quantity < 1) {
+ ElMessageBox.alert("鏈鐢熶骇鏁伴噺蹇呴』澶т簬绛変簬1", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ });
+ return;
+ }
+
+ // 鎶ュ簾鏁伴噺蹇呴』鏄暣鏁颁笖澶т簬绛変簬0
+ if (isNaN(scrapQty) || !Number.isInteger(scrapQty) || scrapQty < 0) {
+ ElMessageBox.alert("鎶ュ簾鏁伴噺蹇呴』澶т簬绛変簬0", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ });
+ return;
+ }
+
+ // if (quantity > reportForm.planQuantity) {
+ // ElMessageBox.alert("鏈鐢熶骇鏁伴噺涓嶈兘瓒呰繃寰呯敓浜ф暟閲�", "鎻愮ず", {
+ // confirmButtonText: "纭畾",
+ // });
+ // return;
+ // }
+
+ const submitData = {
+ ...reportForm,
+ quantity: quantity,
+ scrapQty: scrapQty,
+ };
+ addProductMain(submitData).then(res => {
+ if (res.code === 200) {
+ proxy.$modal.msgSuccess("鎶ュ伐鎴愬姛");
+ reportDialogVisible.value = false;
+ getList();
+ } else {
+ ElMessageBox.alert(res.msg || "鎶ュ伐澶辫触", "鎻愮ず", {
+ confirmButtonText: "纭畾",
+ });
+ }
+ });
});
};
@@ -552,7 +1673,12 @@
userListNoPageByTenantId()
.then(res => {
if (res.code === 200) {
- userOptions.value = res.data || [];
+ const list = Array.isArray(res.data) ? res.data : [];
+ userOptions.value = [
+ { nickName: "浠绘剰鐢ㄦ埛", userId: "-1" },
+ ...deepClone(list),
+ ];
+ userTeamOptions.value = deepClone(list);
}
})
.catch(err => {
@@ -561,30 +1687,117 @@
};
// 鐢ㄦ埛閫夋嫨鍙樺寲鏃舵洿鏂� userName
- const handleUserChange = (userId) => {
+ const handleUserChange = userId => {
if (userId) {
const selectedUser = userOptions.value.find(user => user.userId === userId);
if (selectedUser) {
- reportForm.userName = selectedUser.userName;
+ reportForm.userName = selectedUser.nickName;
}
} else {
reportForm.userName = "";
}
};
- onMounted(() => {
- getList();
+ const handleTeamListChange = val => {
+ if (!Array.isArray(val)) return;
+ let hasString = false;
+ const newList = val.map(item => {
+ if (typeof item === "string") {
+ hasString = true;
+ return { userName: item };
+ }
+ return item;
+ });
+
+ if (hasString) {
+ reportForm.teamList = newList;
+ }
+
+ // 瑙e喅 allow-create 鍦� multiple 妯″紡涓嬭緭鍏ユ鍐呭涓嶈嚜鍔ㄦ竻绌虹殑闂
+ setTimeout(() => {
+ if (teamSelectRef.value) {
+ // 1. 娓呴櫎鍐呴儴 query 鐘舵��
+ teamSelectRef.value.query = "";
+ if (teamSelectRef.value.states) {
+ teamSelectRef.value.states.query = "";
+ teamSelectRef.value.states.inputValue = "";
+ }
+ // 2. 寮哄埗娓呴櫎 DOM 杈撳叆妗嗙殑鍊�
+ const input = teamSelectRef.value.$el?.querySelector("input");
+ if (input) {
+ input.value = "";
+ }
+ // 3. 閽堝鏌愪簺鐗堟湰锛岄噸缃�変腑鏍囩鐨勫唴閮ㄥ亸绉伙紙闃叉杈撳叆妗嗚鎸ゅ崰锛�
+ if (typeof teamSelectRef.value.resetInputState === "function") {
+ teamSelectRef.value.resetInputState();
+ }
+ }
+ }, 50);
+ };
+ // 瀹℃牳浜�
+ const handleReviewerIdChange = userId => {
+ if (userId) {
+ const selectedUser = userOptions.value.find(user => user.userId === userId);
+ if (selectedUser) {
+ reportForm.auditUserName = selectedUser.nickName;
+ }
+ } else {
+ reportForm.auditUserName = "";
+ }
+ };
+
+ const processData = ref([]);
+
+ // 鏌ヨ鎵�鏈夊伐搴�
+ const processLists = async () => {
+ console.log(processData.value);
+ if (processData.value.length > 0) {
+ return processData.value;
+ }
+ const res = await processList();
+
+ processData.value = Array.isArray(res?.data) ? res.data : [];
+ return processData.value;
+ };
+
+ // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁鑳芥帓浜�
+ const canScheduleByWorkOrderNo = row => {
+ if (!row) return false;
+
+ const uid = String(currentUserId.value || "");
+ if (!uid) return false;
+
+ const currentProcess = processData.value.find(
+ item => String(item.id) === String(row.processId)
+ );
+
+ if (!currentProcess) return false;
+
+ const ids = normalizeArray(currentProcess.userIds)
+ .map(id => String(id).trim())
+ .filter(Boolean);
+
+ return ids.includes(uid);
+ };
+
+ onMounted(async () => {
+ await ensureCurrentUser();
+ await processLists();
+ await getList();
getUserList();
+ getDeviceList();
});
</script>
<style scoped lang="scss">
.search_form {
margin-bottom: 20px;
+
.search-row {
display: flex;
gap: 20px;
align-items: center;
+
.search-item {
display: flex;
align-items: center;
@@ -604,26 +1817,32 @@
display: flex;
gap: 20px;
height: 350px;
+
.transfer-card-info {
flex: 1;
overflow: auto;
+
.info-group {
width: 50%;
float: left;
}
+
.info-item {
display: flex;
margin-bottom: 15px;
+
.info-label {
width: 120px;
font-weight: bold;
margin-right: 20px;
}
+
.info-value {
flex: 1;
}
}
}
+
.transfer-card-qr {
width: 240px;
display: flex;
@@ -632,9 +1851,17 @@
justify-content: flex-start;
}
}
+
+ .schedule-user-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 8px;
+ min-height: 32px;
+ align-items: center;
+ }
</style>
-<style lang="scss">
+<style lang="scss">
@media print {
@page {
size: landscape;
@@ -682,20 +1909,24 @@
}
.transfer-card-info {
flex: 1;
+
.info-group {
width: 100%;
float: none;
margin-bottom: 20px;
}
+
.info-item {
display: flex;
margin-bottom: 10px;
+
.info-label {
width: 100px;
font-weight: bold;
margin-right: 15px;
white-space: nowrap;
}
+
.info-value {
flex: 1;
word-break: break-word;
@@ -714,4 +1945,12 @@
height: 140px !important;
}
}
+ .el-table .cell {
+ white-space: normal !important;
+ word-break: break-all;
+ }
+
+ .over-limit .el-input__inner {
+ color: #f56c6c !important;
+ }
</style>
--
Gitblit v1.9.3