| src/api/productionManagement/productWorkOrderFile.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/productionManagement/workOrder.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productStructure/Detail/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionDispatching/components/formDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionReporting/components/formDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrder/components/filesDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/productionManagement/productWorkOrderFile.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,29 @@ import request from "@/utils/request"; // æ¥è¯¢å·¥åéä»¶å表 export function productWorkOrderFileListPage(query) { return request({ url: "/productWorkOrderFile/listPage", method: "get", params: query, }); } // æ°å¢å·¥åéä»¶ export function productWorkOrderFileAdd(data) { return request({ url: "/productWorkOrderFile/add", method: "post", data, }); } // å é¤å·¥åéä»¶ export function productWorkOrderFileDel(data) { return request({ url: "/productWorkOrderFile/del", method: "delete", data, }); } src/api/productionManagement/workOrder.js
@@ -23,3 +23,13 @@ data: data, }); } // ä¸è½½å·¥åæµè½¬å¡ï¼è¿åæä»¶æµï¼ export function downProductWorkOrder(id) { return request({ url: "/productWorkOrder/down", method: "post", data: { id }, responseType: "blob", }); } src/views/productionManagement/productStructure/Detail/index.vue
@@ -2,85 +2,136 @@ <div class="app-container"> <PageHeader content="产åç»æè¯¦æ "> <template #right-button> <el-button v-if="!dataValue.isEdit && !isOrderPage" type="primary" @click="dataValue.isEdit = true">ç¼è¾ <el-button v-if="!dataValue.isEdit && !isOrderPage" type="primary" @click="dataValue.isEdit = true">ç¼è¾ </el-button> <el-button v-if="dataValue.isEdit && !isOrderPage" type="primary" @click="cancelEdit">åæ¶ <el-button v-if="dataValue.isEdit && !isOrderPage" type="primary" @click="cancelEdit">åæ¶ </el-button> <el-button v-if="!isOrderPage" type="primary" :loading="dataValue.loading" @click="submit" <el-button v-if="!isOrderPage" type="primary" :loading="dataValue.loading" @click="submit" :disabled="!dataValue.isEdit">确认 </el-button> </template> </PageHeader> <el-table :data="tableData" border :preserve-expanded-content="false" :default-expand-all="true" <el-table :data="tableData" border :preserve-expanded-content="false" :default-expand-all="true" style="width: 100%"> <el-table-column type="expand"> <template #default="props"> <el-form ref="form" :model="dataValue"> <el-table :data="dataValue.dataList" row-key="tempId" default-expand-all :tree-props="{ children: 'children', hasChildren: 'hasChildren' }" style="width: 100%"> <el-table-column prop="productName" label="产å" /> <el-table-column prop="model" label="è§æ ¼"> <el-form ref="form" :model="dataValue"> <el-table :data="dataValue.dataList" row-key="tempId" default-expand-all :tree-props="{children: 'children', hasChildren: 'hasChildren'}" style="width: 100%"> <el-table-column prop="productName" label="产å" /> <el-table-column prop="model" label="è§æ ¼"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :rules="[{ required: true, message: 'è¯·éæ©è§æ ¼', trigger: ['blur', 'change'] }]" style="margin: 0"> <el-select v-model="row.model" placeholder="è¯·éæ©è§æ ¼" clearable :rules="[{ required: true, message: 'è¯·éæ©è§æ ¼', trigger: ['blur','change'] }]" style="margin: 0"> <el-select v-model="row.model" placeholder="è¯·éæ©è§æ ¼" clearable :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" style="width: 100%" @visible-change="(v) => { if (v) openDialog(row.tempId) }"> <el-option v-if="row.model" :label="row.model" :value="row.model" /> style="width: 100%" @visible-change="(v) => { if (v) openDialog(row.tempId) }"> <el-option v-if="row.model" :label="row.model" :value="row.model" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="processName" label="æ¶èå·¥åº"> <el-table-column prop="processName" label="æ¶èå·¥åº"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :rules="dataValue.dataList.some(item => (item as any).tempId === row.tempId) ? [] : [{ required: true, message: 'è¯·éæ©æ¶èå·¥åº', trigger: 'change' }]" style="margin: 0"> <el-select v-model="row.processId" placeholder="è¯·éæ©" filterable clearable style="width: 100%" <el-select v-model="row.processId" placeholder="è¯·éæ©" filterable clearable style="width: 100%" :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)"> <el-option v-for="item in dataValue.processOptions" :key="item.id" :label="item.name" <el-option v-for="item in dataValue.processOptions" :key="item.id" :label="item.name" :value="item.id" /> </el-select> </el-form-item> </template> </el-table-column> <el-table-column prop="unitQuantity" label="åä½äº§åºæéæ°é"> <el-table-column prop="unitQuantity" label="åä½äº§åºæéæ°é"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :rules="[{ required: true, message: '请è¾å ¥åä½äº§åºæéæ°é', trigger: ['blur', 'change'] }]" style="margin: 0"> <el-input-number v-model="row.unitQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" <el-input-number v-model="row.unitQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" /> </el-form-item> </template> </el-table-column> <el-table-column v-if="isOrderPage" prop="demandedQuantity" label="éæ±æ»é"> <el-table-column v-if="isOrderPage" prop="demandedQuantity" label="éæ±æ»é"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :rules="[{ required: true, message: '请è¾å ¥éæ±æ»é', trigger: ['blur', 'change'] }]" style="margin: 0"> <el-input-number v-model="row.demandedQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" :rules="[{ required: true, message: '请è¾å ¥éæ±æ»é', trigger: ['blur','change'] }]" style="margin: 0"> <el-input-number v-model="row.demandedQuantity" :min="0" :precision="2" :step="1" controls-position="right" style="width: 100%" :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" /> </el-form-item> </template> </el-table-column> <el-table-column prop="unit" label="åä½"> <el-table-column prop="unit" label="åä½"> <template #default="{ row, $index }"> <el-form-item v-if="dataValue.isEdit" :rules="[{ required: true, message: '请è¾å ¥åä½', trigger: ['blur', 'change'] }]" style="margin: 0"> <el-input v-model="row.unit" placeholder="请è¾å ¥åä½" clearable :rules="[{ required: true, message: '请è¾å ¥åä½', trigger: ['blur','change'] }]" style="margin: 0"> <el-input v-model="row.unit" placeholder="请è¾å ¥åä½" clearable :disabled="!dataValue.isEdit || dataValue.dataList.some(item => (item as any).tempId === row.tempId)" /> </el-form-item> </template> </el-table-column> <el-table-column label="æä½" fixed="right" width="200"> <el-table-column label="æä½" fixed="right" width="200"> <template #default="{ row, $index }"> <el-button v-if="dataValue.isEdit && !dataValue.dataList.some(item => (item as any).tempId === row.tempId)" type="danger" text @click="removeItem(row.tempId)">å é¤ <el-button v-if="dataValue.isEdit && !dataValue.dataList.some(item => (item as any).tempId === row.tempId)" type="danger" text @click="removeItem(row.tempId)">å é¤ </el-button> <el-button v-if="dataValue.isEdit" type="primary" text @click="addItem2(row.tempId)">æ·»å <el-button v-if="dataValue.isEdit" type="primary" text @click="addItem2(row.tempId)">æ·»å </el-button> </template> </el-table-column> @@ -88,11 +139,15 @@ </el-form> </template> </el-table-column> <el-table-column label="BOMç¼å·" prop="bomNo" /> <el-table-column label="产ååç§°" prop="productName" /> <el-table-column label="è§æ ¼åå·" prop="model" /> <el-table-column label="BOMç¼å·" prop="bomNo" /> <el-table-column label="产ååç§°" prop="productName" /> <el-table-column label="è§æ ¼åå·" prop="model" /> </el-table> <product-select-dialog v-if="dataValue.showProductDialog" v-model:model-value="dataValue.showProductDialog" <product-select-dialog v-if="dataValue.showProductDialog" v-model:model-value="dataValue.showProductDialog" @confirm="handleProduct" /> </div> </template> @@ -287,11 +342,11 @@ isValid = false; return; } if (!item.unit) { ElMessage.error("请è¾å ¥åä½"); isValid = false; return; } // if (!item.unit) { // ElMessage.error("请è¾å ¥åä½"); // isValid = false; // return; // } // é彿 ¡éªå项 if (item.children && item.children.length > 0) { @@ -425,6 +480,18 @@ return false; }; const getPropPath = (row, field) => { // 为æ¯ä¸ªrowçæå¯ä¸çè·¯å¾ // 使ç¨row.idæç´¢å¼ä½ä¸ºå¯ä¸æ è¯ let path = "dataList"; // ç®åå®ç°ï¼ä½¿ç¨rowçidæä¸ä¸ªå¯ä¸æ è¯ const uniqueId = row.id || Math.floor(Math.random() * 10000); path += `.${uniqueId}`; return path + `.${field}`; }; const cancelEdit = () => { dataValue.isEdit = false; // dataValue.dataList = dataValue.dataList.filter(item => item.id !== undefined); src/views/productionManagement/productionDispatching/components/formDia.vue
@@ -111,6 +111,7 @@ <script setup> import {ref} from "vue"; import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import {productionDispatch} from "@/api/productionManagement/productionOrder.js"; import useUserStore from "@/store/modules/user.js"; src/views/productionManagement/productionReporting/components/formDia.vue
@@ -94,6 +94,7 @@ <script setup> import {ref} from "vue"; import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import {productionReport, productionReportUpdate} from "@/api/productionManagement/productionReporting.js"; const { proxy } = getCurrentInstance() src/views/productionManagement/workOrder/components/filesDia.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,202 @@ <template> <div> <el-dialog v-model="dialogVisible" title="å·¥åéä»¶" width="50%" @close="closeDia"> <div style="margin-bottom: 10px; text-align: right"> <el-upload v-model:file-list="fileList" class="upload-demo" :action="uploadUrl" :on-success="handleUploadSuccess" :on-error="handleUploadError" :before-upload="beforeUpload" name="file" :show-file-list="false" :headers="headers" accept="image/*" style="display: inline; margin-right: 10px" > <el-button type="primary">ä¸ä¼ å¾ç</el-button> </el-upload> <el-button type="danger" plain @click="handleDelete">å é¤</el-button> </div> <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :total="page.total" :tableLoading="tableLoading" :isSelection="true" @selection-change="handleSelectionChange" @pagination="paginationSearch" height="500" /> <template #footer> <div class="dialog-footer"> <el-button @click="closeDia">å ³é</el-button> </div> </template> </el-dialog> <filePreview ref="filePreviewRef" /> </div> </template> <script setup> import { ref, reactive, getCurrentInstance } from "vue"; import { ElMessageBox } from "element-plus"; import { getToken } from "@/utils/auth.js"; import PIMTable from "@/components/PIMTable/PIMTable.vue"; import filePreview from "@/components/filePreview/index.vue"; import { productWorkOrderFileAdd, productWorkOrderFileDel, productWorkOrderFileListPage, } from "@/api/productionManagement/productWorkOrderFile.js"; const { proxy } = getCurrentInstance(); const emit = defineEmits(["close"]); const dialogVisible = ref(false); const currentWorkOrderId = ref(""); const selectedRows = ref([]); const filePreviewRef = ref(); const tableColumn = ref([ { label: "æä»¶åç§°", prop: "name", }, { dataType: "action", label: "æä½", align: "center", width: 120, operation: [ { name: "ä¸è½½", type: "text", clickFun: row => { proxy.$download.name(row.url); }, }, { name: "é¢è§", type: "text", clickFun: row => { filePreviewRef.value?.open(row.url); }, }, ], }, ]); const page = reactive({ current: 1, size: 100, total: 0, }); const tableData = ref([]); const fileList = ref([]); const tableLoading = ref(false); const headers = ref({ Authorization: "Bearer " + getToken(), }); const uploadUrl = ref(import.meta.env.VITE_APP_BASE_API + "/file/upload"); const beforeUpload = file => { const isImage = file?.type?.startsWith("image/"); if (!isImage) { proxy.$modal.msgError("åªè½ä¸ä¼ å¾çæä»¶"); } return isImage; }; const openDialog = row => { dialogVisible.value = true; currentWorkOrderId.value = row.id; page.current = 1; getList(); }; const closeDia = () => { dialogVisible.value = false; emit("close"); }; const paginationSearch = obj => { page.current = obj.page; page.size = obj.limit; getList(); }; const getList = () => { tableLoading.value = true; productWorkOrderFileListPage({ workOrderId: currentWorkOrderId.value, current: page.current, size: page.size, }) .then(res => { tableData.value = res.data.records || []; page.total = res.data.total || 0; }) .finally(() => { tableLoading.value = false; }); }; const handleSelectionChange = selection => { selectedRows.value = selection; }; function handleUploadSuccess(res) { if (res.code == 200) { const fileRow = { name: res.data.originalName, url: res.data.tempPath, workOrderId: currentWorkOrderId.value, }; productWorkOrderFileAdd(fileRow).then(() => { proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); getList(); }); } else { proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); } } function handleUploadError() { proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); } const handleDelete = () => { if (selectedRows.value.length === 0) { proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); return; } const ids = selectedRows.value.map(item => item.id); ElMessageBox.confirm("éä¸çå 容å°è¢«å é¤ï¼æ¯å¦ç¡®è®¤å é¤ï¼", "å é¤", { confirmButtonText: "确认", cancelButtonText: "åæ¶", type: "warning", }) .then(() => { productWorkOrderFileDel(ids).then(() => { proxy.$modal.msgSuccess("å 餿å"); getList(); }); }) .catch(() => { proxy.$modal.msg("已忶"); }); }; defineExpose({ openDialog, }); </script> <style scoped></style> src/views/productionManagement/workOrder/index.vue
@@ -209,6 +209,7 @@ </span> </template> </el-dialog> <FilesDia ref="workOrderFilesRef" /> </div> </template> @@ -220,10 +221,12 @@ 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 tableColumn = ref([ @@ -307,7 +310,13 @@ { name: "æµè½¬å¡", clickFun: row => { showTransferCard(row); downloadAndPrintWorkOrder(row); }, }, { name: "éä»¶", clickFun: row => { openWorkOrderFiles(row); }, }, { @@ -330,6 +339,7 @@ const transferCardQrUrl = ref(""); const transferCardRowData = ref(null); const reportDialogVisible = ref(false); const workOrderFilesRef = ref(null); const userOptions = ref([]); const reportForm = reactive({ planQuantity: 0, @@ -395,6 +405,56 @@ }); }; // ä¸è½½å¹¶æå°å·¥åæµè½¬å¡ï¼æä»¶æµï¼ 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); 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("ä¸è½½å·¥åæµè½¬å¡å¤±è´¥"); } }; const showTransferCard = async row => { transferCardRowData.value = row; const qrContent = String(row.id); @@ -450,6 +510,10 @@ reportDialogVisible.value = true; }; const openWorkOrderFiles = row => { workOrderFilesRef.value?.openDialog(row); }; const handleReport = () => { if (reportForm.planQuantity <= 0) { ElMessageBox.alert("å¾ ç产æ°é为0ï¼æ æ³æ¥å·¥", "æç¤º", {