| 昨天 | spring | ![]() |
| 昨天 | gongchunyi | ![]() |
| 昨天 | gongchunyi | ![]() |
| 昨天 | gongchunyi | ![]() |
| 昨天 | gongchunyi | ![]() |
| 昨天 | gongchunyi | ![]() |
| src/api/inventoryManagement/stockManage.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/productionManagement/productBom.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/productionManagement/workOrder.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/issueManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/inventoryManagement/stockManagement/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productStructure/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/workOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/api/inventoryManagement/stockManage.js
@@ -80,4 +80,38 @@ }) } // // 采购入库-库存管理-冻结不合格产品 export function frozenQuality(ids) { return request({ url: '/stockin/frozenStorageQuality', method: 'post', data: ids }) } // 采购入库-库存管理-解冻不合格产品 export function thawQuality(ids) { return request({ url: '/stockin/thawStorageQuality', method: 'post', data: ids }) } // 成品入库-库存管理-冻结不合格产品 export function frozenFinishedQuality(ids) { return request({ url: '/stockin/frozenFinishedQuality', method: 'post', data: ids }) } // 成品入库-库存管理-解冻不合格产品 export function thawFinishedQuality(ids) { return request({ url: '/stockin/thawFinishedQuality', method: 'post', data: ids }) } src/api/productionManagement/productBom.js
@@ -45,3 +45,22 @@ params: { productModelId }, }); } // 导出BOM export function exportBom(bomId) { return request({ url: "/productBom/exportBom", method: "post", params: { bomId }, responseType: "blob", }); } // 下载模板 export function downloadTemplate() { return request({ url: "/productBom/downloadTemplate", method: "get", responseType: "blob", }); } 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/inventoryManagement/issueManagement/index.vue
@@ -51,12 +51,22 @@ prop="inboundNum0" width="90" show-overflow-tooltip /> <el-table-column label="状态" align="center" prop="isFrozen" width="100"> <template #default="scope"> <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'"> {{ scope.row.isFrozen ? '已冻结' : '正常' }} </el-tag> </template> </el-table-column> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button :disabled="scope.row.inboundNum0 <= 0" <el-button :disabled="scope.row.inboundNum0 <= 0 || scope.row.isFrozen" link type="primary" size="small" @@ -131,13 +141,23 @@ <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" width="150"></el-table-column> <el-table-column label="状态" align="center" prop="isFrozen" width="100"> <template #default="scope"> <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'"> {{ scope.row.isFrozen ? '已冻结' : '正常' }} </el-tag> </template> </el-table-column> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button link :disabled="scope.row.inboundNum0 <= 0" :disabled="scope.row.inboundNum0 <= 0 || scope.row.isFrozen" type="primary" size="small" @click="openForm(scope.row);">领用</el-button> @@ -201,13 +221,23 @@ prop="inboundNum0" width="90" show-overflow-tooltip /> <el-table-column label="状态" align="center" prop="isFrozen" width="100"> <template #default="scope"> <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'"> {{ scope.row.isFrozen ? '已冻结' : '正常' }} </el-tag> </template> </el-table-column> <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button link :disabled="scope.row.inboundNum0 <= 0" :disabled="scope.row.inboundNum0 <= 0 || scope.row.isFrozen" type="primary" size="small" @click="openForm(scope.row);">领用</el-button> @@ -421,6 +451,9 @@ const productModelId = ref(null); // 打开弹框 const openForm = async row => { if (row.isFrozen) { return proxy.$modal.msgError("该产品已冻结,无法领用"); } dialogFormVisible.value = true; currentRowId.value = row.id; currentRowNum.value = row.inboundNum0; src/views/inventoryManagement/stockManagement/index.vue
@@ -25,6 +25,12 @@ </div> <div> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleFrozenFinished">冻结</el-button> <el-button type="success" plain @click="handleThawFinished">解冻</el-button> <!-- <el-button type="danger" plain @click="handleDelete">删除</el-button>--> </div> </div> @@ -71,6 +77,16 @@ <el-table-column label="剩余库存" prop="stockQuantity" show-overflow-tooltip /> <el-table-column label="状态" align="center" prop="isFrozen" width="100"> <template #default="scope"> <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'"> {{ scope.row.isFrozen ? '已冻结' : '正常' }} </el-tag> </template> </el-table-column> <!-- <el-table-column fixed="right" label="操作" min-width="60" align="center"> <template #default="scope"> <el-button link type="primary" size="small" @click="openForm('edit', scope.row);">编辑</el-button> @@ -108,6 +124,12 @@ </div> <div> <el-button @click="handleOut">导出</el-button> <el-button type="danger" plain @click="handleFrozen">冻结</el-button> <el-button type="success" plain @click="handleThaw">解冻</el-button> <!-- <el-button type="danger" plain @click="handleDelete">删除</el-button>--> </div> </div> @@ -164,6 +186,16 @@ <el-table-column label="含税总价(元)" prop="taxInclusiveTotalPrice" width="150"></el-table-column> <el-table-column label="状态" align="center" prop="isFrozen" width="100"> <template #default="scope"> <el-tag :type="scope.row.isFrozen ? 'danger' : 'success'"> {{ scope.row.isFrozen ? '已冻结' : '正常' }} </el-tag> </template> </el-table-column> </el-table> <pagination v-show="total > 0" :total="total" @@ -200,6 +232,10 @@ getStockManagePage, getStockManagePageByProduction, delStockManage, getStockManageProduction, frozenQuality, thawQuality, frozenFinishedQuality, thawFinishedQuality, } from "@/api/inventoryManagement/stockManage.js"; import { updateManagement, @@ -534,6 +570,108 @@ proxy.$modal.msg("已取消"); }); }; // 冻结 const handleFrozen = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.salesLedgerProductId); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被标记为不合格产品并冻结,是否确认?", "警告", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { frozenQuality(ids).then(res => { proxy.$modal.msgSuccess("操作成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 原料解冻 const handleThaw = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.id); } else { proxy.$modal.msgWarning("请选择数据"); return; } ElMessageBox.confirm("选中的内容将被解冻,是否确认?", "提示", { confirmButtonText: "确认", cancelButtonText: "取消", type: "success", }) .then(() => { thawQuality(ids).then(res => { proxy.$modal.msgSuccess("操作成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 成品冻结 const handleFrozenFinished = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.productId); } else { proxy.$modal.msgWarning("请选择数据"); return; } console.log(ids); ElMessageBox.confirm("选中的内容将被标记为不合格产品并冻结,是否确认?", "警告", { confirmButtonText: "确认", cancelButtonText: "取消", type: "warning", }) .then(() => { frozenFinishedQuality(ids).then(res => { proxy.$modal.msgSuccess("操作成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 成品解冻 const handleThawFinished = () => { let ids = []; if (selectedRows.value.length > 0) { ids = selectedRows.value.map(item => item.productId); } else { proxy.$modal.msgWarning("请选择数据"); return; } console.log(ids); ElMessageBox.confirm("选中的内容将被解冻,是否确认?", "提示", { confirmButtonText: "确认", cancelButtonText: "取消", type: "success", }) .then(() => { thawFinishedQuality(ids).then(res => { proxy.$modal.msgSuccess("操作成功"); getList(); }); }) .catch(() => { proxy.$modal.msg("已取消"); }); }; // 删除 const handleDelete = () => { let ids = []; src/views/productionManagement/productStructure/index.vue
@@ -1,42 +1,26 @@ <template> <div class="app-container"> <div style="text-align: right; margin-bottom: 10px;"> <el-button type="info" plain icon="Upload" @click="handleImport" v-hasPermi="['product:bom:import']">导入</el-button> <el-button type="warning" plain icon="Download" @click="handleExport" :disabled="selectedRows.length !== 1" v-hasPermi="['product:bom:export']">导出</el-button> <el-button type="primary" @click="handleAdd">新增</el-button> <el-button type="danger" plain @click="handleBatchDelete" :disabled="selectedRows.length === 0">删除</el-button> </div> <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination" > <template #detail="{row}"> <el-button type="primary" text @click="showDetail(row)">{{ row.bomNo }} <PIMTable rowKey="id" :column="tableColumn" :tableData="tableData" :page="page" :isSelection="true" @selection-change="handleSelectionChange" :tableLoading="tableLoading" @pagination="pagination"> <template #detail="{ row }"> <el-button type="primary" text @click="showDetail(row)">{{ row.bomNo }} </el-button> </template> </PIMTable> <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow"/> <StructureEdit v-if="showEdit" v-model:show-model="showEdit" :record="currentRow" /> <!-- 新增/编辑弹窗 --> <el-dialog v-model="dialogVisible" :title="operationType === 'add' ? '新增BOM' : '编辑BOM'" width="600px" @close="closeDialog" > <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" > <el-dialog v-model="dialogVisible" :title="operationType === 'add' ? '新增BOM' : '编辑BOM'" width="600px" @close="closeDialog"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px"> <el-form-item label="产品名称" prop="productModelId"> <el-button type="primary" @click="showProductSelectDialog = true"> {{ form.productName || '选择产品' }} @@ -46,13 +30,7 @@ <el-input v-model="form.version" placeholder="请输入版本号" clearable /> </el-form-item> <el-form-item label="备注" prop="remark"> <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable /> <el-input v-model="form.remark" type="textarea" :rows="3" placeholder="请输入备注" clearable /> </el-form-item> </el-form> <template #footer> @@ -60,22 +38,26 @@ <el-button type="primary" @click="handleSubmit">确定</el-button> </template> </el-dialog> <!-- 产品选择弹窗 --> <ProductSelectDialog v-model="showProductSelectDialog" @confirm="handleProductSelect" single /> <ProductSelectDialog v-model="showProductSelectDialog" @confirm="handleProductSelect" single /> <!-- BOM导入对话框 --> <ImportDialog ref="uploadRef" v-model="upload.open" :title="upload.title" :action="upload.url" :headers="upload.headers" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :show-download-template="true" @confirm="submitFileForm" @download-template="handleDownloadTemplate" @close="handleImportClose" /> </div> </template> <script setup> import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from "vue"; import { listPage, add, update, batchDelete } from "@/api/productionManagement/productBom.js"; import { getToken } from "@/utils/auth"; import { listPage, add, update, batchDelete, exportBom, downloadTemplate } from "@/api/productionManagement/productBom.js"; import { useRouter } from 'vue-router' import { ElMessageBox } from 'element-plus' import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; import ImportDialog from "@/components/Dialog/ImportDialog.vue"; const router = useRouter() const { proxy } = getCurrentInstance() @@ -92,7 +74,7 @@ { label: "产品名称", prop: "productName", minWidth: 160 }, { @@ -145,6 +127,20 @@ const operationType = ref('add'); // add | edit const formRef = ref(null); const showProductSelectDialog = ref(false); // BOM导入参数 const upload = reactive({ // 是否显示弹出层(BOM导入) open: false, // 弹出层标题(BOM导入) title: "", // 是否禁用上传 isUploading: false, // 设置上传的请求头部 headers: { Authorization: "Bearer " + getToken() }, // 上传的地址 url: import.meta.env.VITE_APP_BASE_API + "/productBom/uploadBom" }); const page = reactive({ current: 1, @@ -246,7 +242,7 @@ proxy.$modal.msgError('删除失败'); }); }) .catch(() => {}); .catch(() => { }); }; // 批量删除 @@ -271,7 +267,7 @@ proxy.$modal.msgError('删除失败'); }); }) .catch(() => {}); .catch(() => { }); }; // 产品选择 @@ -321,6 +317,103 @@ formRef.value?.resetFields(); }; // 导入按钮操作 const handleImport = () => { upload.title = "BOM导入"; upload.open = true; }; // 关闭导入对话框时清除文件 const handleImportClose = () => { proxy.$refs["uploadRef"].clearFiles(); }; // 文件上传中处理 const handleFileUploadProgress = (event, file, fileList) => { upload.isUploading = true; }; // 文件上传成功处理 const handleFileSuccess = (response, file, fileList) => { upload.open = false; upload.isUploading = false; proxy.$refs["uploadRef"].clearFiles(); if (response.code === 200) { proxy.$modal.msgSuccess(response.msg || "导入成功"); getList(); } else { proxy.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true }); } }; // 提交上传文件 const submitFileForm = () => { proxy.$refs["uploadRef"].submit(); }; // 导出按钮操作 const handleExport = () => { if (selectedRows.value.length !== 1) { proxy.$modal.msgWarning("请选择一条数据进行导出"); return; } const bomId = selectedRows.value[0].id; const fileName = `BOM_${selectedRows.value[0].bomNo || bomId}.xlsx`; exportBom(bomId).then(res => { // 返回的数据是否为空 if (!res) { proxy.$modal.msgError("导出失败,返回数据为空"); return; } const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const downloadElement = document.createElement('a'); const href = window.URL.createObjectURL(blob); downloadElement.style.display = 'none'; downloadElement.href = href; downloadElement.download = fileName; document.body.appendChild(downloadElement); downloadElement.click(); document.body.removeChild(downloadElement); window.URL.revokeObjectURL(href); proxy.$modal.msgSuccess("导出成功"); }).catch(err => { console.error("导出异常:", err); proxy.$modal.msgError("系统异常,导出失败"); }); }; // 下载模板 const handleDownloadTemplate = async () => { const res = await downloadTemplate(); // 返回的数据是否为空 if (!res) { proxy.$modal.msgError("下载失败,返回数据为空"); return; } const blob = new Blob([res], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); const downloadElement = document.createElement('a'); const href = window.URL.createObjectURL(blob); downloadElement.href = href; downloadElement.download = "BOM模板.xlsx"; document.body.appendChild(downloadElement); downloadElement.click(); document.body.removeChild(downloadElement); window.URL.revokeObjectURL(href); proxy.$modal.msgSuccess("下载成功"); }; // 查看详情 const showDetail = (row) => { router.push({ src/views/productionManagement/workOrder/index.vue
@@ -221,6 +221,7 @@ productWorkOrderPage, updateProductWorkOrder, addProductMain, downProductWorkOrder, } from "@/api/productionManagement/workOrder.js"; import { getUserProfile, userListNoPageByTenantId } from "@/api/system/user.js"; import QRCode from "qrcode"; @@ -309,7 +310,7 @@ { name: "流转卡", clickFun: row => { showTransferCard(row); downloadAndPrintWorkOrder(row); }, }, { @@ -404,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);