| src/router/index.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionOrder/Detail/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrder/components/CopperPrintingForm.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| vite.config.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/router/index.js
@@ -106,6 +106,21 @@ }, ], }, // ç产订å-ç产详æ ï¼å·¥åºè¿åº¦ï¼ { path: "/productionManagement/productionOrder/detail", component: Layout, hidden: true, children: [ { path: "", component: () => import("@/views/productionManagement/productionOrder/Detail/index.vue"), name: "ProductionOrderDetail", meta: { title: "ç产详æ ", activeMenu: "/productionManagement/productionOrder" }, }, ], }, ]; // å¨æè·¯ç±ï¼åºäºç¨æ·æé卿å»å è½½ src/views/productionManagement/productionOrder/Detail/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,499 @@ <template> <div class="app-container production-order-detail"> <PageHeader content="ç产详æ "> </PageHeader> <el-card shadow="never" class="mb12"> <div class="header"> <div class="title">åºç¡ä¿¡æ¯</div> <div class="sub"> <span class="mr12">ç产订åå·ï¼{{ header.npsNo || "-" }}</span> <span class="mr12">ç产æ¹å·ï¼{{ header.lotNo || "-" }}</span> <span class="mr12">产ååç§°ï¼{{ header.productCategory || "-" }}</span> <span class="mr12">è§æ ¼ï¼{{ header.specificationModel || "-" }}</span> </div> </div> </el-card> <el-card shadow="never" class="mb12"> <div class="steps-head"> <div class="steps-title">å·¥åºæ§è¡è¿åº¦</div> </div> <div class="steps-body"> <div class="steps-left"> <div class="steps-wrap"> <el-steps class="process-steps" :active="active" finish-status="success" direction="vertical" > <el-step v-for="(p, idx) in processes" :key="p.processCode || idx" > <template #title> <div class="step-title" :class="{ selected: idx === selectedIndex }" @click="selectProcess(idx)" > {{ `${idx + 1}. ${p.processName || "-"}` }} </div> </template> <template #description> <div class="step-panel"> <div v-if="idx === active" class="current-progress"> <div class="current-progress-head"> <span class="current-progress-title">å½åå·¥åºè¿åº¦</span> <!-- <span class="current-progress-value">{{ currentProcessPercentage }}%</span> --> </div> <el-progress :percentage="currentProcessPercentage" :status="currentProcessPercentage >= 100 ? 'success' : ''" :stroke-width="10" /> </div> <div class="step-meta"> <span class="meta-item"> <span class="meta-label">å·¥åºç¼å·</span> <span class="meta-value">{{ p.processCode || "-" }}</span> </span> <span class="meta-item"> <span class="meta-label">ä¸è¯ç</span> <span class="meta-value danger">{{ defectRateText(p) }}</span> </span> </div> <div class="step-grid"> <div class="grid-item"> <div class="grid-label">æå ¥æ°é</div> <div class="grid-value">{{ p.inputQty ?? 0 }}</div> </div> <div class="grid-item"> <div class="grid-label">äº§åºæ°é</div> <div class="grid-value">{{ p.outputQty ?? 0 }}</div> </div> <div class="grid-item"> <div class="grid-label">åæ ¼æ°é</div> <div class="grid-value success">{{ p.qualifiedQty ?? 0 }}</div> </div> <div class="grid-item"> <div class="grid-label">ä¸è¯æ°é</div> <div class="grid-value danger">{{ p.badQty ?? 0 }}</div> </div> </div> </div> </template> </el-step> </el-steps> </div> </div> <div class="steps-right"> <div class="right-panel"> <div class="right-panel-head"> <div class="right-title">æ¥å·¥ä¿¡æ¯</div> <div class="right-sub" v-if="selectedProcess"> å½åå·¥åºï¼{{ selectedProcess.processName }}ï¼{{ selectedProcess.processCode }}ï¼ </div> </div> <div v-if="!selectedProcess" class="right-empty"> ç¹å»å·¦ä¾§æä¸ªå·¥åºï¼å³ä¾§å±ç¤ºè¯¥å·¥åºçæ¥å·¥æç»ã </div> <div v-else class="right-content"> <el-table :data="mockReports" border height="420"> <el-table-column label="åºå·" type="index" width="60" align="center" /> <el-table-column label="æ¥å·¥åå·" prop="reportNo" min-width="140" show-overflow-tooltip /> <el-table-column label="æ¥å·¥äººå" prop="reportUser" min-width="120" show-overflow-tooltip /> <el-table-column label="æ¥å·¥æ¶é´" prop="reportTime" min-width="160" show-overflow-tooltip /> <el-table-column label="äº§åºæ°é" prop="outputQty" min-width="110" /> <el-table-column label="ä¸è¯æ°é" prop="badQty" min-width="110" /> <el-table-column label="夿³¨" prop="remark" min-width="160" show-overflow-tooltip /> </el-table> </div> </div> </div> </div> </el-card> </div> </template> <script setup> import { computed, ref } from "vue"; import { useRoute, useRouter } from "vue-router"; const route = useRoute(); const header = computed(() => ({ orderId: route.query.orderId, npsNo: route.query.npsNo, lotNo: route.query.lotNo, productCategory: route.query.productCategory, specificationModel: route.query.specificationModel, })); // 模æå·¥åºæ°æ®ï¼åç»ç¨æ¥å£æ¿æ¢ï¼ const processes = computed(() => [ { processCode: "GX-001", processName: "夿", inputQty: 1000, outputQty: 980, qualifiedQty: 970, badQty: 10, status: "success", }, { processCode: "GX-002", processName: "æå", inputQty: 980, outputQty: 960, qualifiedQty: 948, badQty: 12, status: "process", }, { processCode: "GX-003", processName: "çå¹²", inputQty: 960, outputQty: 950, qualifiedQty: 948, badQty: 2, status: "wait", }, { processCode: "GX-004", processName: "å è£ å ¥åº", inputQty: 950, outputQty: 920, qualifiedQty: 918, badQty: 2, status: "wait", }, ]); const selectedIndex = ref(null); const selectProcess = (idx) => { selectedIndex.value = idx; }; const selectedProcess = computed(() => { if (selectedIndex.value === null || selectedIndex.value === undefined) return null; return (processes.value || [])[selectedIndex.value] || null; }); // æ¨¡ææ¥å·¥ä¿¡æ¯ï¼åç»ç¨æ¥å£æ¿æ¢ï¼ const mockReports = computed(() => { const p = selectedProcess.value; if (!p) return []; const code = p.processCode || "GX"; return [ { reportNo: `${code}-BG-0001`, reportUser: "å¼ ä¸", reportTime: "2026-03-14 09:20", outputQty: Math.floor((p.outputQty ?? 0) * 0.4), badQty: Math.floor((p.badQty ?? 0) * 0.4), remark: "æ£å¸¸æ¥å·¥", }, { reportNo: `${code}-BG-0002`, reportUser: "æå", reportTime: "2026-03-14 13:45", outputQty: Math.floor((p.outputQty ?? 0) * 0.35), badQty: Math.floor((p.badQty ?? 0) * 0.35), remark: "设å¤è°è¯åæ¢å¤", }, { reportNo: `${code}-BG-0003`, reportUser: "çäº", reportTime: "2026-03-14 17:10", outputQty: Math.max(0, (p.outputQty ?? 0) - Math.floor((p.outputQty ?? 0) * 0.75)), badQty: Math.max(0, (p.badQty ?? 0) - Math.floor((p.badQty ?? 0) * 0.75)), remark: "æ¶å°¾", }, ]; }); const clampPercentage = (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); }; // el-steps: active 为å½åè¿è¡ä¸çæ¥éª¤ä¸æ ï¼æ¨¡æï¼ const active = computed(() => { const list = processes.value || []; const idx = list.findIndex((p) => p.status === "process"); return idx >= 0 ? idx : 0; }); const currentProcess = computed(() => { const list = processes.value || []; return list[active.value] || null; }); // å½åå·¥åºè¿åº¦ï¼ç¨äº§åº/æå ¥ä¼°ç®ï¼UI å è·éï¼åç»æçå®è§åæ¿æ¢ï¼ const currentProcessPercentage = computed(() => { const p = currentProcess.value; if (!p) return 0; const input = Number(p.inputQty ?? 0); const output = Number(p.outputQty ?? 0); if (!Number.isFinite(input) || input <= 0) return 0; return clampPercentage((output / input) * 100); }); // ä¸è¯çï¼ä¸è¯æ°é / äº§åºæ°éï¼å ææ¤å£å¾ï¼åç»å¯¹æ¥æ¥å£å¯è°æ´ï¼ const defectRateText = (p) => { const bad = Number(p?.badQty ?? 0); const output = Number(p?.outputQty ?? 0); if (!Number.isFinite(bad) || bad <= 0) return "0%"; if (!Number.isFinite(output) || output <= 0) return "0%"; const rate = (bad / output) * 100; return `${rate.toFixed(2)}%`; }; </script> <style scoped lang="scss"> .production-order-detail { // 左侧æ¥éª¤åºçå¯è§é«åº¦ï¼éå±å¹é«åº¦èªéåº // è¿éåå»é¡µé¢é¡¶é¨ï¼PageHeader + åºç¡ä¿¡æ¯å¡ç + è¾¹è·çï¼ç大è´é«åº¦ --steps-left-height: calc(100vh - 320px); .header { display: flex; flex-direction: column; gap: 8px; .title { font-size: 16px; font-weight: 600; color: #303133; } .sub { color: #606266; display: flex; flex-wrap: wrap; row-gap: 6px; } } .steps-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; .steps-title { font-size: 14px; font-weight: 600; color: #303133; } .steps-desc { font-size: 12px; color: #909399; } } .steps-wrap { padding: 4px 0 0; height: 100%; overflow-y: auto; } .steps-body { display: flex; gap: 16px; align-items: flex-start; } .steps-left { flex: 0 0 50%; max-width: 50%; min-width: 0; height: var(--steps-left-height); overflow: hidden; } .steps-right { flex: 1; min-width: 0; } .step-title { cursor: pointer; display: inline-flex; align-items: center; padding: 2px 6px; border-radius: 6px; transition: background-color 0.15s ease; &:hover { background: #f5f7fa; } &.selected { background: rgba(64, 158, 255, 0.12); color: #409eff; } } .process-steps { width: 100%; :deep(.el-step__title) { font-weight: 600; } :deep(.el-step__description) { font-size: 12px; color: #606266; line-height: 18px; margin-top: 8px; width: 100%; } :deep(.el-step__main) { padding-bottom: 20px; width: 100%; } :deep(.el-step__icon.is-text) { border-color: #dcdfe6; } :deep(.el-step.is-vertical) { align-items: flex-start; } :deep(.el-step__head) { width: 28px; flex: 0 0 28px; } :deep(.el-step__main) { flex: 1; min-width: 0; padding-right: 6px; } } .step-panel { background: #f6f8fb; border: 1px solid #ebeef5; border-radius: 10px; padding: 12px 12px 10px; width: 100%; max-width: none; box-sizing: border-box; } .right-panel { border: 1px solid #ebeef5; border-radius: 10px; background: #ffffff; padding: 12px; min-height: 520px; box-sizing: border-box; } .right-panel-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: 12px; } .right-title { font-size: 14px; font-weight: 700; color: #303133; } .right-sub { font-size: 12px; color: #909399; } .right-empty { height: 100%; min-height: 460px; display: flex; align-items: center; justify-content: center; color: #909399; background: #fafafa; border: 1px dashed #dcdfe6; border-radius: 10px; } .current-progress { background: #ffffff; border: 1px dashed #dcdfe6; border-radius: 10px; padding: 10px 12px 8px; margin-bottom: 10px; .current-progress-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } .current-progress-title { color: #303133; font-weight: 600; font-size: 12px; } .current-progress-value { color: #606266; font-size: 12px; font-weight: 600; } } .step-meta { display: flex; gap: 16px; margin-bottom: 10px; .meta-item { display: inline-flex; gap: 8px; align-items: center; } .meta-label { color: #909399; } .meta-value { color: #303133; font-weight: 600; &.danger { color: #f56c6c; } } } .step-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; .grid-item { background: #ffffff; border: 1px solid #ebeef5; border-radius: 10px; padding: 10px 10px 8px; } .grid-label { font-size: 12px; color: #909399; margin-bottom: 6px; } .grid-value { font-size: 16px; font-weight: 700; color: #303133; &.success { color: #67c23a; } &.danger { color: #f56c6c; } } } .mb12 { margin-bottom: 12px; } .mr12 { margin-right: 12px; } } </style> src/views/productionManagement/productionOrder/index.vue
@@ -58,11 +58,13 @@ @selection-change="handleSelectionChange" @pagination="pagination"> <template #completionStatus="{ row }"> <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" /> <div class="progress-link" @click="goProductionDetail(row)"> <el-progress :percentage="toProgressPercentage(row?.completionStatus)" :color="progressColor(toProgressPercentage(row?.completionStatus))" :status="toProgressPercentage(row?.completionStatus) >= 100 ? 'success' : ''" /> </div> </template> </PIMTable> </div> @@ -213,6 +215,7 @@ { name: "å·¥èºè·¯çº¿", type: "text", showHide: row => row.processRouteCode, clickFun: row => { showRouteItemModal(row); }, @@ -422,6 +425,20 @@ }); }; const goProductionDetail = (row) => { if (!row) return; router.push({ path: "/productionManagement/productionOrder/detail", query: { orderId: row.id, npsNo: row.npsNo || "", lotNo: row.lotNo || "", productCategory: row.productCategory || "", specificationModel: row.specificationModel || "", }, }); }; // è¡¨æ ¼éæ©æ°æ® const handleSelectionChange = (selection) => { selectedRows.value = selection; @@ -491,4 +508,8 @@ ::v-deep .purple{ background-color: #F4DEFA; } .progress-link { cursor: pointer; } </style> src/views/productionManagement/workOrder/components/CopperPrintingForm.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,443 @@ <script setup lang="ts"> import {computed, onMounted, reactive, ref} from "vue"; import dayjs from "dayjs"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import {ElMessage} from "element-plus"; import {addProductMain} from "@/api/productionManagement/workOrder.js"; defineOptions({ name: "CopperPrintingForm" }); const props = defineProps({ isShow: { type: Boolean, required: true }, isEdit: { type: Boolean, default: false }, detailData: { type: Object, default: () => ({}), }, row: { type: Object, default: () => ({}), } }); const emits = defineEmits(["update:isShow", "refreshData"]); const visible = computed({ get: () => props.isShow, set: (value: boolean) => emits("update:isShow", value), }); const formData = reactive({ productProcessRouteItemId: undefined, workOrderId: undefined, planQuantity: undefined, reportWork: undefined, productMainId: undefined, quantity: undefined, // ç§éäº§åºæ¿ userId: undefined, // ä½ä¸å userName: undefined, // ä½ä¸å otherData: { dryingTemperature: '', // ç干温度 startTime: dayjs().format('YYYY-MM-DD HH:mm:ss'), // å¼å§æ¶é´ endTime: dayjs().format('YYYY-MM-DD HH:mm:ss'), // ç»ææ¶é´ userId: undefined, // ä½ä¸å userName: undefined, // ä½ä¸å underlyingCopperPaste: undefined, // åºå±éæµ underlyingCopperPastePrintingQuantity: undefined, // åºå±éæµå°å·æ¬¡æ° underlyingCopperPasteMachineNumber: undefined, // åºå±éæµæºå°å· underlyingCopperPasteSilkScreenFamilyNumber: undefined, // åºå±éæµä¸ç½æå· underlyingCopperPasteNumberOfEyes: undefined, // åºå±éæµç®æ° underlyingCopperPasteUserId: undefined, // åºå±éæµä½ä¸å underlyingCopperPasteUserName: undefined, // åºå±éæµä½ä¸å underlyingCopperPasteDryingTemperature: undefined, // åºå±éæµç干温度 surfaceCopperPaste: undefined, // 表å±éæµ surfaceCopperPastePrintingQuantity: undefined, // 表å±éæµå°å·æ¬¡æ° surfaceCopperPasteMachineNumber: undefined, // 表å±éæµæºå°å· surfaceCopperPasteSilkScreenFamilyNumber: undefined, // 表å±éæµä¸ç½æå· surfaceCopperPasteNumberOfEyes: undefined, // 表å±éæµç®æ° surfaceCopperPasteUserId: undefined, // 表å±éæµä½ä¸å surfaceCopperPasteUserName: undefined, // 表å±éæµä½ä¸å surfaceCopperPasteDryingTemperature: undefined, // 表å±éæµç干温度, steelBurningDate: undefined, // ç§é¢æ¥æ copperFiringTime: undefined, // ç§éè¿çæ¶é´ steelFiringTime: undefined, // ç§é¢åºçæ¶é´ weight: undefined, // ééï¼kg/posï¼ copperSmeltingTemperatureProfile: undefined, // ç§é温度æ²çº¿ remark: undefined, // 夿³¨ } }) const userOptions = ref([]); const getUserList = () => { userListNoPageByTenantId() .then(res => { if (res.code === 200) { userOptions.value = res.data || []; } }) .catch(err => { console.error("è·åç¨æ·å表失败", err); }); }; // ç¨æ·éæ©ååæ¶æ´æ° userName const handleUserChange = (userId: any, reportType: string) => { if (userId) { const selectedUser = userOptions.value.find(user => user.userId === userId); switch (reportType) { case 'userId': formData.otherData.userName = selectedUser.userName; break; case 'underlyingCopperPasteUserId': formData.otherData.underlyingCopperPasteUserName = selectedUser.userName; break; case 'surfaceCopperPasteUserId': formData.otherData.surfaceCopperPasteUserName = selectedUser.userName; break; } } else { switch (reportType) { case 'userId': formData.otherData.userName = ""; break; case 'underlyingCopperPasteUserId': formData.otherData.underlyingCopperPasteUserName = ""; break; case 'surfaceCopperPasteUserId': formData.otherData.surfaceCopperPasteUserName = ""; break; } } }; const handleReport = () => { if (!formData.otherData.userId && !formData.otherData.surfaceCopperPasteUserId && !formData.otherData.underlyingCopperPasteUserId) { ElMessage.error('è¯·éæ©ä½ä¸å') return; } if (!formData.quantity || formData.quantity <= 0) { ElMessage.error('请è¾å ¥ç产æ°é') return; } formData.userId = formData.otherData.surfaceCopperPasteUserId || formData.otherData.underlyingCopperPasteUserId; const otherData = JSON.stringify(formData.otherData); const submitData = { ...formData, otherData: otherData }; addProductMain(submitData).then(res => { if (res.code === 200) { ElMessage({ message: 'æ¥å·¥æå', type: 'success', }) emits("refreshData") visible.value = false; } else { ElMessage.error('æ¥å·¥å¤±è´¥') } }); }; const initData = () => { if (!props.isEdit) { formData.otherData = JSON.parse(props.detailData.otherData || '{}'); formData.quantity = props.detailData.quantity; } else { const row = props.row; formData.planQuantity = row.planQuantity formData.productProcessRouteItemId = row.productProcessRouteItemId formData.workOrderId = row.id formData.reportWork = row.reportWork formData.productMainId = row.productMainId } } const displayValue = (value: any) => { return value === undefined || value === null || value === "" ? "-" : value; }; onMounted(() => { getUserList(); initData() }) </script> <template> <el-dialog v-model="visible" title="å°éæ¥å·¥" width="90%"> <el-form :model="formData"> <table class="report-table"> <tbody> <tr> <td class="tip" colspan="4">ç·çæ¸ æ´åæ¾ç½®æ¶é´è¶ è¿72Hï¼éæ°ççåæè½å°å·å¹¶å¡«åæ¬æ </td> <td class="label" colspan="3">ç干温度</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.dryingTemperature" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.dryingTemperature) }}</span> </td> <td class="label">å¼å§æ¶é´</td> <td colspan="2"> <el-date-picker v-if="props.isEdit" v-model="formData.otherData.startTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="è¯·éæ©" style="width: 100%" /> <span v-else class="view-value">{{ displayValue(formData.otherData.startTime) }}</span> </td> <td class="label" colspan="3">ç»ææ¶é´</td> <td colspan="2"> <el-date-picker v-if="props.isEdit" v-model="formData.otherData.endTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="è¯·éæ©" style="width: 100%" /> <span v-else class="view-value">{{ displayValue(formData.otherData.endTime) }}</span> </td> <td class="label" colspan="2">ä½ä¸å</td> <td colspan="2"> <el-select v-model="formData.otherData.userId" v-if="props.isEdit" style="width: 100%" placeholder="è¯·éæ©ä½ä¸å" clearable filterable @change="handleUserChange($event, 'userId')"> <el-option v-for="user in userOptions" :key="user.userId" :label="user.userName" :value="user.userId"/> </el-select> <span v-else class="view-value">{{ displayValue(formData.otherData.userName || formData.otherData.userId) }}</span> </td> </tr> <tr> <td class="label" colspan="2">åºå±éæµ</td> <td> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPaste" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPaste) }}</span> </td> <td class="label">å°å·æ¬¡æ°</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPastePrintingQuantity" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPastePrintingQuantity) }}</span> </td> <td class="label">æºå°å·</td> <td> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPasteMachineNumber" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPasteMachineNumber) }}</span> </td> <td class="label">ä¸ç½æå·</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPasteSilkScreenFamilyNumber" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPasteSilkScreenFamilyNumber) }}</span> </td> <td class="label">ç®æ°</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPasteNumberOfEyes" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPasteNumberOfEyes) }}</span> </td> <td class="label">ä½ä¸å</td> <td colspan="2"> <el-select v-model="formData.otherData.underlyingCopperPasteUserId" v-if="props.isEdit" style="width: 100%" placeholder="è¯·éæ©ä½ä¸å" clearable filterable @change="handleUserChange($event, 'underlyingCopperPasteUserId')"> <el-option v-for="user in userOptions" :key="user.userId" :label="user.userName" :value="user.userId"/> </el-select> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPasteUserName || formData.otherData.underlyingCopperPasteUserId) }}</span> </td> <td class="label" colspan="2">ç干温度</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.underlyingCopperPasteDryingTemperature" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.underlyingCopperPasteDryingTemperature) }}</span> </td> </tr> <tr> <td class="label" colspan="2">表å±éæµ</td> <td> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPaste" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPaste) }}</span> </td> <td class="label">å°å·æ¬¡æ°</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPastePrintingQuantity" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPastePrintingQuantity) }}</span> </td> <td class="label">æºå°å·</td> <td> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPasteMachineNumber" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPasteMachineNumber) }}</span> </td> <td class="label">ä¸ç½æå·</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPasteSilkScreenFamilyNumber" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPasteSilkScreenFamilyNumber) }}</span> </td> <td class="label">ç®æ°</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPasteNumberOfEyes" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPasteNumberOfEyes) }}</span> </td> <td class="label">ä½ä¸å</td> <td colspan="2"> <el-select v-model="formData.otherData.surfaceCopperPasteUserId" v-if="props.isEdit" style="width: 100%" placeholder="è¯·éæ©ä½ä¸å" clearable filterable @change="handleUserChange($event, 'surfaceCopperPasteUserId')"> <el-option v-for="user in userOptions" :key="user.userId" :label="user.userName" :value="user.userId"/> </el-select> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPasteUserName || formData.otherData.surfaceCopperPasteUserId) }}</span> </td> <td class="label" colspan="2">ç干温度</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.surfaceCopperPasteDryingTemperature" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.surfaceCopperPasteDryingTemperature) }}</span> </td> </tr> <tr> <td class="label" colspan="2">ç§é¢æ¥æ</td> <td colspan="2"> <el-date-picker v-if="props.isEdit" v-model="formData.otherData.steelBurningDate" type="date" value-format="YYYY-MM-DD" format="YYYY-MM-DD" placeholder="è¯·éæ©" style="width: 100%" /> <span v-else class="view-value">{{ displayValue(formData.otherData.steelBurningDate) }}</span> </td> <td class="label" colspan="3">ç§éè¿çæ¶é´</td> <td colspan="2"> <el-date-picker v-if="props.isEdit" v-model="formData.otherData.copperFiringTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="è¯·éæ©" style="width: 100%" /> <span v-else class="view-value">{{ displayValue(formData.otherData.copperFiringTime) }}</span> </td> <td class="label">ç§é¢åºçæ¶é´</td> <td colspan="2"> <el-date-picker v-if="props.isEdit" v-model="formData.otherData.steelFiringTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" format="YYYY-MM-DD HH:mm:ss" placeholder="è¯·éæ©" style="width: 100%" /> <span v-else class="view-value">{{ displayValue(formData.otherData.steelFiringTime) }}</span> </td> <td class="label" colspan="3">ç§éäº§åºæ¿</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.quantity" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.quantity) }}</span> </td> <td class="label" colspan="2">éé(kg/pos)</td> <td colspan="2"> <el-input v-if="props.isEdit" v-model="formData.otherData.weight" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.weight) }}</span> </td> </tr> <tr> <td class="label" colspan="2">ç§é温度æ²çº¿</td> <td colspan="7"> <el-input v-if="props.isEdit" v-model="formData.otherData.copperSmeltingTemperatureProfile" type="textarea" :rows="3" placeholder="请è¾å ¥" /> <span v-else class="view-value">{{ displayValue(formData.otherData.copperSmeltingTemperatureProfile) }}</span> </td> <td class="label">夿³¨</td> <td colspan="11"> <el-input v-if="props.isEdit" v-model="formData.otherData.remark" type="textarea" :rows="3" placeholder="请è¾å ¥"/> <span v-else class="view-value">{{ displayValue(formData.otherData.remark) }}</span> </td> </tr> </tbody> </table> </el-form> <template #footer> <span class="dialog-footer"> <el-button v-if="props.isEdit" type="primary" @click="handleReport">ç¡®å®</el-button> <el-button @click="visible = false">{{ props.isEdit ? "åæ¶" : "å ³é" }}</el-button> </span> </template> </el-dialog> </template> <style scoped> .report-table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 13px; } .report-table td { border: 1px solid #dcdfe6; padding: 6px; vertical-align: middle; } .report-table .label { width: 90px; background: #f5f7fa; text-align: center; font-weight: 500; } .report-table .tip { text-align: center; font-weight: 500; line-height: 1.4; background: #fafafa; } .view-value { display: inline-block; min-height: 32px; line-height: 32px; } </style> src/views/productionManagement/workOrder/index.vue
@@ -10,11 +10,12 @@ placeholder="请è¾å ¥" @change="handleQuery" clearable prefix-icon="Search" /> prefix-icon="Search"/> </div> <div class="search-item"> <el-button type="primary" @click="handleQuery">æç´¢</el-button> @click="handleQuery">æç´¢ </el-button> </div> </div> </div> @@ -25,10 +26,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="ç¼è¾æ¶é´" @@ -40,28 +43,28 @@ type="date" placeholder="è¯·éæ©" value-format="YYYY-MM-DD" style="width: 300px" /> style="width: 300px"/> </el-form-item> <el-form-item label="计åç»ææ¶é´"> <el-date-picker v-model="editrow.planEndTime" type="date" placeholder="è¯·éæ©" value-format="YYYY-MM-DD" style="width: 300px" /> style="width: 300px"/> </el-form-item> <el-form-item label="å®é å¼å§æ¶é´"> <el-date-picker v-model="editrow.actualStartTime" type="date" placeholder="è¯·éæ©" value-format="YYYY-MM-DD" style="width: 300px" /> style="width: 300px"/> </el-form-item> <el-form-item label="å®é ç»ææ¶é´"> <el-date-picker v-model="editrow.actualEndTime" type="date" placeholder="è¯·éæ©" value-format="YYYY-MM-DD" style="width: 300px" /> style="width: 300px"/> </el-form-item> </el-form> <template #footer> @@ -105,7 +108,7 @@ transferCardRowData.status }}</span> </div> --> <div class="info-item"> <span class="info-label">计åå¼å§æ¶é´</span> <span class="info-value">{{ transferCardRowData.planStartTime }}</span> @@ -150,7 +153,7 @@ <div class="qr-container"> <img :src="transferCardQrUrl" alt="æµè½¬å¡äºç»´ç " style="width: 200px; height: 200px;" /> style="width: 200px; height: 200px;"/> <!-- <div class="qr-tip" style="margin-top: 10px; text-align: center;">æµè½¬å¡äºç»´ç </div> --> </div> @@ -161,7 +164,8 @@ 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" @@ -174,7 +178,7 @@ <el-form-item label="å¾ ç产æ°é"> <el-input v-model="reportForm.planQuantity" readonly style="width: 300px" /> style="width: 300px"/> </el-form-item> <el-form-item label="æ¬æ¬¡ç产æ°é" prop="quantity"> <el-input v-model.number="reportForm.quantity" @@ -183,7 +187,7 @@ step="1" style="width: 300px" placeholder="请è¾å ¥æ¬æ¬¡ç产æ°é" @input="handleQuantityInput" /> @input="handleQuantityInput"/> </el-form-item> <el-form-item label="æ¥åºæ°é" prop="scrapQty"> <el-input v-model.number="reportForm.scrapQty" @@ -192,7 +196,7 @@ step="1" style="width: 300px" placeholder="请è¾å ¥æ¥åºæ°é" @input="handleScrapQtyInput" /> @input="handleScrapQtyInput"/> </el-form-item> <el-form-item label="çç»ä¿¡æ¯"> <el-select v-model="reportForm.userId" @@ -204,7 +208,7 @@ <el-option v-for="user in userOptions" :key="user.userId" :label="user.userName" :value="user.userId" /> :value="user.userId"/> </el-select> </el-form-item> </el-form> @@ -216,308 +220,318 @@ </span> </template> </el-dialog> <FilesDia ref="workOrderFilesRef" /> <FilesDia ref="workOrderFilesRef"/> <CopperPrintingForm v-if="copperPrintingFormVisible" v-model:isShow="copperPrintingFormVisible" :isEdit="true" :row="currentReportRowData" @refreshData="getList"/> </div> </template> <script setup> import { onMounted, ref, nextTick } from "vue"; import { ElMessageBox } from "element-plus"; import dayjs from "dayjs"; import { productWorkOrderPage, updateProductWorkOrder, addProductMain, downProductWorkOrder, } 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"; const { proxy } = getCurrentInstance(); const { priority_type } = proxy.useDict("priority_type"); import {onMounted, ref, nextTick} from "vue"; import {ElMessageBox} from "element-plus"; import dayjs from "dayjs"; import { productWorkOrderPage, updateProductWorkOrder, addProductMain, downProductWorkOrder, } 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"; const tableColumn = ref([ { label: "ä¼å 级", prop: "priority", width: '100px', dataType: "tag", formatData: val => proxy.selectDictLabel(priority_type.value, val), formatType: val => { const v = Number(val); if (v === 0) return "danger"; // çº¢è² if (v === 1) return "warning"; // é»è² if (v === 2) return "success"; // ç»¿è² return ""; const {proxy} = getCurrentInstance(); const {priority_type} = proxy.useDict("priority_type"); const CopperPrintingForm = defineAsyncComponent(() => import("./components/CopperPrintingForm.vue")); const tableColumn = ref([ { label: "ä¼å 级", prop: "priority", width: '100px', dataType: "tag", formatData: val => proxy.selectDictLabel(priority_type.value, val), formatType: val => { const v = Number(val); if (v === 0) return "danger"; // çº¢è² if (v === 1) return "warning"; // é»è² if (v === 2) return "success"; // ç»¿è² return ""; }, }, // { // label: "å·¥åç±»å", // prop: "workOrderType", // width: "80", // }, { label: "å·¥åç¼å·", prop: "workOrderNo", width: "140", }, { label: "ç产订åå·", prop: "productOrderNpsNo", width: "140", }, { label: "产ååç§°", prop: "productName", width: "140", }, { label: "è§æ ¼", prop: "model", }, { label: "åä½", prop: "unit", }, { label: "å·¥åºåç§°", prop: "processName", }, { label: "éæ±æ°é", prop: "planQuantity", width: "140", }, { label: "宿æ°é", prop: "completeQuantity", width: "140", }, { label: "宿è¿åº¦", prop: "completionStatus", dataType: "slot", slot: "completionStatus", width: "140", }, { label: "计åå¼å§æ¶é´", prop: "planStartTime", width: "140", }, { label: "计åç»ææ¶é´", prop: "planEndTime", width: "140", }, { label: "å®é å¼å§æ¶é´", prop: "actualStartTime", width: "140", }, { label: "å®é ç»ææ¶é´", prop: "actualEndTime", width: "140", }, { label: "æä½", width: "200", align: "center", dataType: "action", fixed: "right", operation: [ { name: "ç¼è¾", clickFun: row => { handleEdit(row); handleEdit(row); }, }, }, // { // label: "å·¥åç±»å", // prop: "workOrderType", // width: "80", // }, { label: "å·¥åç¼å·", prop: "workOrderNo", width: "140", }, { label: "ç产订åå·", prop: "productOrderNpsNo", width: "140", }, { label: "产ååç§°", prop: "productName", width: "140", }, { label: "è§æ ¼", prop: "model", }, { label: "åä½", prop: "unit", }, { label: "å·¥åºåç§°", prop: "processName", }, { label: "éæ±æ°é", prop: "planQuantity", width: "140", }, { label: "宿æ°é", prop: "completeQuantity", width: "140", }, { label: "宿è¿åº¦", prop: "completionStatus", dataType: "slot", slot: "completionStatus", width: "140", }, { label: "计åå¼å§æ¶é´", prop: "planStartTime", width: "140", }, { label: "计åç»ææ¶é´", prop: "planEndTime", width: "140", }, { label: "å®é å¼å§æ¶é´", prop: "actualStartTime", width: "140", }, { label: "å®é ç»ææ¶é´", prop: "actualEndTime", width: "140", }, { label: "æä½", width: "200", align: "center", dataType: "action", fixed: "right", operation: [ { name: "ç¼è¾", clickFun: row => { handleEdit(row); }, { name: "æµè½¬å¡", clickFun: row => { downloadAndPrintWorkOrder(row); }, { name: "æµè½¬å¡", clickFun: row => { downloadAndPrintWorkOrder(row); }, }, { name: "éä»¶", clickFun: row => { openWorkOrderFiles(row); }, { name: "éä»¶", clickFun: row => { openWorkOrderFiles(row); }, }, { name: "æ¥å·¥", clickFun: row => { showReportDialog(row); }, { name: "æ¥å·¥", clickFun: row => { showReportDialog(row); }, disabled: row => row.planQuantity <= 0, }, ], }, ]); const tableData = ref([]); const tableLoading = ref(false); const qrCodeUrl = ref(""); const qrRowData = ref(null); const editDialogVisible = ref(false); const transferCardVisible = ref(false); const transferCardData = ref([]); const transferCardQrUrl = ref(""); const transferCardRowData = ref(null); const reportDialogVisible = ref(false); const workOrderFilesRef = ref(null); const reportFormRef = ref(null); const userOptions = ref([]); const reportForm = reactive({ planQuantity: 0, quantity: null, scrapQty: null, userName: "", workOrderId: "", reportWork: "", productProcessRouteItemId: "", userId: "", productMainId: null, }); // æ¬æ¬¡ç产æ°ééªè¯è§å 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 reportFormRules = { quantity: [ { required: true, validator: validateQuantity, trigger: 'blur' } disabled: row => row.planQuantity <= 0, }, ], scrapQty: [ { validator: validateScrapQty, trigger: 'blur' } ] }; // å¤çæ¬æ¬¡ç产æ°éè¾å ¥ï¼éå¶å¿ 须大äºçäº1 const handleQuantityInput = (value) => { if (value === '' || value === null || value === undefined) { }, ]); const tableData = ref([]); const tableLoading = ref(false); const qrCodeUrl = ref(""); const qrRowData = ref(null); const editDialogVisible = ref(false); const copperPrintingFormVisible = ref(false); const transferCardVisible = ref(false); const transferCardData = ref([]); const transferCardQrUrl = ref(""); const transferCardRowData = ref(null); const reportDialogVisible = ref(false); const workOrderFilesRef = ref(null); const reportFormRef = ref(null); const userOptions = ref([]); const reportForm = reactive({ planQuantity: 0, quantity: null, scrapQty: null, userName: "", workOrderId: "", reportWork: "", productProcessRouteItemId: "", userId: "", productMainId: null, }); // æ¬æ¬¡ç产æ°ééªè¯è§å 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 reportFormRules = { quantity: [ {required: true, validator: validateQuantity, trigger: 'blur'} ], scrapQty: [ {validator: validateScrapQty, trigger: 'blur'} ] }; // å¤çæ¬æ¬¡ç产æ°éè¾å ¥ï¼éå¶å¿ 须大äºçäº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; } 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); // 妿æ¯NaNï¼ä¿æåå¼ 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, size: 100, total: 0, }); reportForm.quantity = intValue; return; } reportForm.quantity = num; }; const data = reactive({ searchForm: { workOrderNo: "", }, }); const { searchForm } = toRefs(data); 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"; }; let editrow = ref(null); // å¤çæ¥åºæ°é const handleScrapQtyInput = (value) => { if (value === '' || value === null || value === undefined) { reportForm.scrapQty = null; return; } const num = Number(value); // 妿æ¯NaNï¼ä¿æåå¼ 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, size: 100, total: 0, }); // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); }; const pagination = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; const params = { ...searchForm.value, ...page }; productWorkOrderPage(params) const data = reactive({ searchForm: { workOrderNo: "", }, }); const {searchForm} = toRefs(data); 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"; }; let editrow = ref(null); // æ¥è¯¢å表 /** æç´¢æé®æä½ */ const handleQuery = () => { page.current = 1; getList(); }; const pagination = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; const params = {...searchForm.value, ...page}; productWorkOrderPage(params) .then(res => { tableLoading.value = false; tableData.value = res.data.records; @@ -526,77 +540,77 @@ .catch(() => { tableLoading.value = false; }); }; }; // ä¸è½½å¹¶æå°å·¥åæµè½¬å¡ï¼æä»¶æµï¼ const downloadAndPrintWorkOrder = async row => { if (!row || !row.id) { proxy.$modal.msgError("缺å°å·¥åIDï¼æ æ³ä¸è½½æµè½¬å¡"); return; } const fileName = row.workOrderNo // ä¸è½½å¹¶æå°å·¥åæµè½¬å¡ï¼æä»¶æµï¼ const downloadAndPrintWorkOrder = async row => { if (!row || !row.id) { proxy.$modal.msgError("缺å°å·¥åIDï¼æ æ³ä¸è½½æµè½¬å¡"); return; } const fileName = row.workOrderNo ? `å·¥åæµè½¬å¡_${row.workOrderNo}.xlsx` : "å·¥åæµè½¬å¡.xlsx"; try { // è°ç¨æ¥å£ï¼ä»¥ responseType: 'blob' è·åæä»¶æµ const blob = await downProductWorkOrder(row.id); try { // è°ç¨æ¥å£ï¼ä»¥ responseType: 'blob' è·åæä»¶æµ const blob = await downProductWorkOrder(row.id); if (!blob) { proxy.$modal.msgError("æªè·åå°æµè½¬å¡æä»¶"); return; } // å建 Blob URL const fileBlob = blob instanceof Blob ? blob : new Blob([blob], { type: blob.type || "application/octet-stream" }); const url = window.URL.createObjectURL(fileBlob); // å建éè iframeï¼ç¨äºè§¦åæµè§å¨æå° const iframe = document.createElement("iframe"); iframe.style.position = "fixed"; iframe.style.right = "0"; iframe.style.bottom = "0"; iframe.style.width = "0"; iframe.style.height = "0"; iframe.style.border = "0"; iframe.src = url; document.body.appendChild(iframe); iframe.onload = () => { try { iframe.contentWindow?.focus(); iframe.contentWindow?.print(); } catch (e) { console.error("èªå¨è°ç¨æå°å¤±è´¥", e); // éèæ±å ¶æ¬¡ï¼æå¼æ°çªå£ç±ç¨æ·æå¨æå° window.open(url); } }; } catch (e) { console.error("ä¸è½½å·¥åæµè½¬å¡å¤±è´¥", e); proxy.$modal.msgError("ä¸è½½å·¥åæµè½¬å¡å¤±è´¥"); if (!blob) { proxy.$modal.msgError("æªè·åå°æµè½¬å¡æä»¶"); return; } }; const showTransferCard = async row => { transferCardRowData.value = row; const qrContent = String(row.id); // å建 Blob URL const fileBlob = blob instanceof Blob ? blob : new Blob([blob], {type: blob.type || "application/octet-stream"}); const url = window.URL.createObjectURL(fileBlob); transferCardQrUrl.value = await QRCode.toDataURL(qrContent); transferCardVisible.value = true; }; // å建éè iframeï¼ç¨äºè§¦åæµè§å¨æå° const iframe = document.createElement("iframe"); iframe.style.position = "fixed"; iframe.style.right = "0"; iframe.style.bottom = "0"; iframe.style.width = "0"; iframe.style.height = "0"; iframe.style.border = "0"; iframe.src = url; document.body.appendChild(iframe); const printTransferCard = () => { window.print(); }; iframe.onload = () => { try { iframe.contentWindow?.focus(); iframe.contentWindow?.print(); } catch (e) { console.error("èªå¨è°ç¨æå°å¤±è´¥", e); // éèæ±å ¶æ¬¡ï¼æå¼æ°çªå£ç±ç¨æ·æå¨æå° window.open(url); } }; } catch (e) { console.error("ä¸è½½å·¥åæµè½¬å¡å¤±è´¥", e); proxy.$modal.msgError("ä¸è½½å·¥åæµè½¬å¡å¤±è´¥"); } }; const handleEdit = row => { editrow.value = JSON.parse(JSON.stringify(row)); editDialogVisible.value = true; }; const showTransferCard = async row => { transferCardRowData.value = row; const qrContent = String(row.id); const handleUpdate = () => { updateProductWorkOrder(editrow.value) transferCardQrUrl.value = await QRCode.toDataURL(qrContent); transferCardVisible.value = true; }; const printTransferCard = () => { window.print(); }; const handleEdit = row => { editrow.value = JSON.parse(JSON.stringify(row)); editDialogVisible.value = true; }; const handleUpdate = () => { updateProductWorkOrder(editrow.value) .then(res => { proxy.$modal.msgSuccess("æäº¤æå"); editDialogVisible.value = false; @@ -607,22 +621,26 @@ confirmButtonText: "ç¡®å®", }); }); }; }; const showReportDialog = row => { currentReportRowData.value = row; reportForm.planQuantity = row.planQuantity; reportForm.quantity = row.quantity !== undefined && row.quantity !== null ? row.quantity : null; reportForm.productProcessRouteItemId = row.productProcessRouteItemId; reportForm.workOrderId = row.id; reportForm.reportWork = row.reportWork; reportForm.productMainId = row.productMainId; reportForm.scrapQty = row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null; nextTick(() => { reportFormRef.value?.clearValidate(); }); // è·åå½åç»å½ç¨æ·ä¿¡æ¯ï¼è®¾ç½®ä¸ºé»è®¤éä¸ getUserProfile() const showReportDialog = row => { currentReportRowData.value = row; if (row.processName === 'å°é') { copperPrintingFormVisible.value = true return } reportForm.planQuantity = row.planQuantity; reportForm.quantity = row.quantity !== undefined && row.quantity !== null ? row.quantity : null; reportForm.productProcessRouteItemId = row.productProcessRouteItemId; reportForm.workOrderId = row.id; reportForm.reportWork = row.reportWork; reportForm.productMainId = row.productMainId; reportForm.scrapQty = row.scrapQty !== undefined && row.scrapQty !== null ? row.scrapQty : null; nextTick(() => { reportFormRef.value?.clearValidate(); }); // è·åå½åç»å½ç¨æ·ä¿¡æ¯ï¼è®¾ç½®ä¸ºé»è®¤éä¸ getUserProfile() .then(res => { if (res.code === 200) { reportForm.userId = res.data.userId; @@ -633,86 +651,86 @@ console.error("è·åç¨æ·ä¿¡æ¯å¤±è´¥", err); }); reportDialogVisible.value = true; }; reportDialogVisible.value = true; }; const openWorkOrderFiles = row => { workOrderFilesRef.value?.openDialog(row); }; const openWorkOrderFiles = row => { workOrderFilesRef.value?.openDialog(row); }; const handleReport = () => { 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 }; // console.log(submitData); addProductMain(submitData).then(res => { if (res.code === 200) { proxy.$modal.msgSuccess("æ¥å·¥æå"); reportDialogVisible.value = false; getList(); } else { ElMessageBox.alert(res.msg || "æ¥å·¥å¤±è´¥", "æç¤º", { confirmButtonText: "ç¡®å®", }); } const handleReport = () => { reportFormRef.value?.validate((valid) => { if (!valid) { return false; } if (reportForm.planQuantity <= 0) { ElMessageBox.alert("å¾ ç产æ°é为0ï¼æ æ³æ¥å·¥", "æç¤º", { confirmButtonText: "ç¡®å®", }); }); }; return; } // è·åç¨æ·å表 const getUserList = () => { userListNoPageByTenantId() // éªè¯æ¬æ¬¡ç产æ°é 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 }; // console.log(submitData); addProductMain(submitData).then(res => { if (res.code === 200) { proxy.$modal.msgSuccess("æ¥å·¥æå"); reportDialogVisible.value = false; getList(); } else { ElMessageBox.alert(res.msg || "æ¥å·¥å¤±è´¥", "æç¤º", { confirmButtonText: "ç¡®å®", }); } }); }); }; // è·åç¨æ·å表 const getUserList = () => { userListNoPageByTenantId() .then(res => { if (res.code === 200) { userOptions.value = res.data || []; @@ -721,160 +739,172 @@ .catch(err => { console.error("è·åç¨æ·å表失败", err); }); }; }; // ç¨æ·éæ©ååæ¶æ´æ° userName const handleUserChange = (userId) => { if (userId) { const selectedUser = userOptions.value.find(user => user.userId === userId); if (selectedUser) { reportForm.userName = selectedUser.userName; } } else { reportForm.userName = ""; // ç¨æ·éæ©ååæ¶æ´æ° userName const handleUserChange = (userId) => { if (userId) { const selectedUser = userOptions.value.find(user => user.userId === userId); if (selectedUser) { reportForm.userName = selectedUser.userName; } }; } else { reportForm.userName = ""; } }; onMounted(() => { getList(); getUserList(); }); onMounted(() => { getList(); getUserList(); }); </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; gap: 10px; } } } .search_form { margin-bottom: 20px; .transfer-card-title { font-size: 24px; font-weight: bold; text-align: center; margin-bottom: 20px; } .transfer-card-container { .search-row { 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; align-items: center; .search-item { display: flex; flex-direction: column; align-items: center; justify-content: flex-start; gap: 10px; } } } .transfer-card-title { font-size: 24px; font-weight: bold; text-align: center; margin-bottom: 20px; } .transfer-card-container { 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; flex-direction: column; align-items: center; justify-content: flex-start; } } </style> <style lang="scss"> @media print { @page { size: landscape; <style lang="scss"> @media print { @page { size: landscape; } body * { visibility: hidden; } .el-dialog__wrapper, .el-dialog, .el-dialog__body, .transfer-card-title, .transfer-card-container, .transfer-card-container *, .info-item, .info-label, .info-value { visibility: visible; } .print-button-container { visibility: hidden; } .el-dialog__wrapper { position: absolute; top: 0; left: 0; right: 0; margin: 0; } .el-dialog { width: 100% !important; max-width: 800px; margin: 0 auto !important; } .el-dialog__header, .el-dialog__footer { display: none; } .el-dialog__body { padding: 20px; } .transfer-card-container { height: auto; display: flex; gap: 20px; } .transfer-card-info { flex: 1; .info-group { width: 100%; float: none; margin-bottom: 20px; } body * { visibility: hidden; } .el-dialog__wrapper, .el-dialog, .el-dialog__body, .transfer-card-title, .transfer-card-container, .transfer-card-container *, .info-item, .info-label, .info-value { visibility: visible; } .print-button-container { visibility: hidden; } .el-dialog__wrapper { position: absolute; top: 0; left: 0; right: 0; margin: 0; } .el-dialog { width: 100% !important; max-width: 800px; margin: 0 auto !important; } .el-dialog__header, .el-dialog__footer { display: none; } .el-dialog__body { padding: 20px; } .transfer-card-container { height: auto; .info-item { display: flex; gap: 20px; } .transfer-card-info { flex: 1; .info-group { width: 100%; float: none; margin-bottom: 20px; margin-bottom: 10px; .info-label { width: 100px; font-weight: bold; margin-right: 15px; white-space: nowrap; } .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; } .info-value { flex: 1; word-break: break-word; } } .transfer-card-qr { width: 160px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; } .qr-container img { width: 140px !important; height: 140px !important; } } .transfer-card-qr { width: 160px; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; } .qr-container img { width: 140px !important; height: 140px !important; } } </style> src/views/qualityManagement/metricMaintenance/StandardFormDialog.vue
@@ -25,6 +25,7 @@ <el-option label="åæææ£éª" value="0" /> <el-option label="è¿ç¨æ£éª" value="1" /> <el-option label="åºåæ£éª" value="2" /> <el-option label="å·¡æ£" value="3" /> </el-select> </el-form-item> <el-form-item label="å·¥åº" prop="processId"> vite.config.js
@@ -7,74 +7,61 @@ const env = loadEnv(mode, process.cwd()); const { VITE_APP_ENV } = env; const baseUrl = env.VITE_APP_ENV === "development" ? "http://192.168.1.35:9009" : env.VITE_BASE_API; env.VITE_APP_ENV === "development" ? "http://1.15.17.182:9009" : env.VITE_BASE_API; const javaUrl = env.VITE_APP_ENV === "development" ? "http://192.168.1.35:9009" : env.VITE_JAVA_API; env.VITE_APP_ENV === "development" ? "http://1.15.17.182:9009" : env.VITE_JAVA_API; return { define: { __BASE_API__: JSON.stringify(javaUrl), define:{ __BASE_API__: JSON.stringify(javaUrl) }, // é¨ç½²ç产ç¯å¢åå¼åç¯å¢ä¸çURLã // é»è®¤æ åµä¸ï¼vite ä¼åè®¾ä½ çåºç¨æ¯è¢«é¨ç½²å¨ä¸ä¸ªååçæ ¹è·¯å¾ä¸ // ä¾å¦ https://www.ruoyi.vip/ã妿åºç¨è¢«é¨ç½²å¨ä¸ä¸ªåè·¯å¾ä¸ï¼ä½ å°±éè¦ç¨è¿ä¸ªé项æå®è¿ä¸ªåè·¯å¾ãä¾å¦ï¼å¦æä½ çåºç¨è¢«é¨ç½²å¨ https://www.ruoyi.vip/admin/ï¼å设置 baseUrl 为 /admin/ã base: VITE_APP_ENV === "production" ? "/" : "/", plugins: createVitePlugins(env, command === "build"), resolve: { // https://cn.vitejs.dev/config/#resolve-alias alias: { // è®¾ç½®è·¯å¾ "~": path.resolve(__dirname, "./"), // 设置å«å "@": path.resolve(__dirname, "./src"), }, // https://cn.vitejs.dev/config/#resolve-extensions extensions: [".mjs", ".js", ".ts", ".jsx", ".tsx", ".json", ".vue"], dedupe: ["vue", "axios"], // å»ééå¤ä¾èµ }, // å ¨å±å¼å¯æå»ºç¼åï¼æ ¸å¿ï¼ cacheDir: "/var/jenkins_home/workspace/客æ·-é¹åçµåå端/node_modules/.vite", // ä¾èµé¢æå»ºä¼å optimizeDeps: { include: ["vue", "axios", "element-plus", "echarts"], // æ ¹æ®é¡¹ç®ä¾èµè°æ´ esbuildOptions: { target: "es2020", }, }, // æå é ç½®ï¼æ ¸å¿ä¼ååºï¼ // æå é ç½® build: { sourcemap: false, // å½»åºå ³éç产ç¯å¢sourcemap // https://vite.dev/config/build-options.html sourcemap: command === "build" ? false : "inline", outDir: "dist", assetsDir: "assets", chunkSizeWarningLimit: 2000, minify: "esbuild", // ä½¿ç¨ esbuild åç¼©ï¼æ éé¢å¤ä¾èµï¼ reportCompressedSize: false, // å ³é产ç©ä½ç§¯æ¥åï¼åå°èæ¶ commonjsOptions: { include: [/node_modules/, /\.commonjs$/], }, rollupOptions: { output: { chunkFileNames: "static/js/[name]-[hash].js", entryFileNames: "static/js/[name]-[hash].js", assetFileNames: "static/[ext]/[name]-[hash].[ext]", // åå çç¥ï¼æå大ä¾èµï¼ manualChunks: { vendor: ["vue", "vue-router", "pinia", "axios"], ui: ["element-plus"], // æ ¹æ®å®é UIåºè°æ´ charts: ["echarts"], // æå¾è¡¨åºåä¿çï¼æ åå é¤ }, }, cache: true, }, }, // vite ç¸å ³é ç½® server: { port: 8001, port: 80, host: true, open: true, proxy: { // https://cn.vitejs.dev/config/#server-proxy "/dev-api": { target: baseUrl, changeOrigin: true, rewrite: (p) => p.replace(/^\/dev-api/, ""), }, // springdoc proxy "^/v3/api-docs/(.*)": { target: baseUrl, changeOrigin: true, @@ -96,20 +83,6 @@ }, ], }, // CSS é¢ç¼è¯ç¼å preprocessorOptions: { scss: { cacheDirectory: path.resolve( __dirname, "./node_modules/.vite/scss-cache" ), }, }, }, // esbuild å ¨å±é ç½® esbuild: { logOverride: { "this-is-undefined-in-esm": "silent" }, target: "es2020", }, }; });