| README.md | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/productionManagement/productionOrder.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/api/salesManagement/salesLedger.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/utils/request.js | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/productionManagement/productionOrder/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/salesManagement/salesLedger/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
README.md
@@ -31,6 +31,9 @@ # å¯å¨æå¡ yarn dev #æå å½ä»¤ yarn build:prod -- --company="JCCK" # æå»ºæµè¯ç¯å¢ yarn build:stage # æå»ºç产ç¯å¢ yarn build:prod # æå»ºç产ç¯å¢ yarn build:prod -- --company="AAA" src/api/productionManagement/productionOrder.js
@@ -145,4 +145,29 @@ method: "patch", data: data, }); } //æ ¹æ®è®¢åçbomIdæ¥è¯¢åºååææ export function getByBomId(query) { return request({ url: "/productOrder/getByBomId", method: "get", params: query, }); } //ä¿åç产订å颿 export function drawMaterials(data) { return request({ url: "/productOrder/drawMaterials", method: "post", data: data, }); } export function getProductOrderBatchNoOptions() { return request({ url: "/productOrder/getProductOrderBatchNo", method: "get", }); } src/api/salesManagement/salesLedger.js
@@ -116,4 +116,14 @@ method: "get", params: query, }); } // å¯¼åº export function saleOutboundExport(query) { return request({ url: '/sales/ledger/exportSaleOutbound', method: 'post', data: query, responseType: 'blob' }) } src/utils/request.js
@@ -72,7 +72,24 @@ }) // ååºæ¦æªå¨ service.interceptors.response.use(res => { service.interceptors.response.use(async res => { const isBlob = res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer' if (isBlob) { const contentType = res.headers['content-type'] if (contentType && contentType.includes('application/json')) { const text = await new Response(res.data).text() const data = JSON.parse(text) const msg = data.msg || '导åºå¤±è´¥' ElMessage.error(msg) return Promise.reject(new Error(msg)) } return res.data } // æªè®¾ç½®ç¶æç åé»è®¤æåç¶æ const code = res.data.code || 200 // è·åéè¯¯ä¿¡æ¯ src/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,226 @@ <template> <el-dialog v-model="visible" title="颿" width="1000px" top="3vh" :close-on-click-modal="false" destroy-on-close class="material-requisition-dialog" > <div class="material-requisition-form"> <!-- åææå表 --> <el-table :data="materialList" border style="width: 100%" height="65vh"> <el-table-column type="index" label="åºå·" width="60" align="center" /> <el-table-column prop="productName" label="产ååç§°" min-width="150" /> <el-table-column prop="model" label="åå·" min-width="150" /> <!-- <el-table-column prop="batchNo" label="æ¹å·" min-width="150"> <template #default="{ row }"> <el-select v-model="row.batchNo" placeholder="è¯·éæ©æ¹å·" clearable style="width: 100%" > <el-option v-for="item in row.batchOptions || []" :key="item.batchNo" :label="item.batchNo" :value="item.batchNo" /> </el-select> </template> </el-table-column> --> <el-table-column prop="unit" label="åä½" width="80" align="center" /> <el-table-column prop="qualitity" label="æ°é" width="100" align="center"> <template #default="{ row }"> {{ row.qualitity || 0 }} </template> </el-table-column> <el-table-column prop="requisitionQty" label="é¢ç¨æ°é" width="120" align="center"> <template #default="{ row }"> <el-input-number v-model="row.requisitionQty" :min="0" :precision="2" :controls="false" :disabled="!row.qualitity || hasDrawMaterials" style="width: 100%" /> </template> </el-table-column> <el-table-column prop="remark" label="夿³¨" min-width="150"> </el-table-column> </el-table> </div> <template #footer> <span class="dialog-footer"> <el-button type="primary" :loading="saving" @click="handleConfirm">ç¡® 认</el-button> <el-button @click="handleCancel">å æ¶</el-button> </span> </template> </el-dialog> </template> <script setup> import { ref, reactive, computed, watch } from 'vue'; import { ElMessage } from 'element-plus'; import { getByBomId, drawMaterials } from '@/api/productionManagement/productionOrder.js'; const props = defineProps({ modelValue: { type: Boolean, default: false }, orderData: { type: Object, default: () => ({}) } }); const emit = defineEmits(['update:modelValue', 'confirm']); const visible = computed({ get: () => props.modelValue, set: (val) => emit('update:modelValue', val) }); const loading = ref(false); const saving = ref(false); const materialList = ref([]); const hasDrawMaterials = ref(false); // çå¬å¼¹æ¡æå¼ï¼å è½½æ°æ® watch(() => props.modelValue, (val) => { if (val && props.orderData) { loadMaterialList(); } }); const loadMaterialList = async () => { const order = props.orderData; const drawMaterialsData = order.drawMaterials; // 妿已æé¢ææ°æ®ï¼ç´æ¥ä½¿ç¨ if (drawMaterialsData) { hasDrawMaterials.value = true; try { const list = typeof drawMaterialsData === 'string' ? JSON.parse(drawMaterialsData) : drawMaterialsData; materialList.value = list.map(item => ({ ...item, requisitionQty: item.requisitionQty || 0 })); return; } catch (e) { console.error('è§£æé¢ææ°æ®å¤±è´¥:', e); } } // 没æé¢ææ°æ®ï¼è°ç¨æ¥å£æ¥è¯¢ hasDrawMaterials.value = false; const bomId = order?.bomId; if (!bomId) { ElMessage.warning('å½å订å缺å°BOMä¿¡æ¯'); return; } loading.value = true; try { const res = await getByBomId({ bomId }); const data = res.data || []; // å¤çæ°æ®ï¼æ·»å é¢ç¨æ°éåæ®µåæ¹å·é项 materialList.value = data.map(item => ({ ...item, requisitionQty: item.qualitity ? 0 : 0, batchNo: item.batchNo || '', remark: item.remark || '', // æ¹å·é项ï¼ä»åºååææä¿¡æ¯ä¸è·å batchOptions: item.inventoryList || [] })); } catch (error) { console.error('æ¥è¯¢åææå表失败:', error); ElMessage.error('æ¥è¯¢åææå表失败'); materialList.value = []; } finally { loading.value = false; } }; const handleCancel = () => { visible.value = false; materialList.value = []; hasDrawMaterials.value = false; }; const handleConfirm = async () => { const orderId = props.orderData?.id; if (!orderId) { ElMessage.error('订åIDä¸åå¨'); return; } const drawMaterialsList = materialList.value.map(item => ({ ...item, requisitionQty: item.requisitionQty || 0 })); const postData = { id: orderId, drawMaterials: JSON.stringify(drawMaterialsList) }; saving.value = true; try { await drawMaterials(postData); ElMessage.success('颿ä¿åæå'); visible.value = false; materialList.value = []; hasDrawMaterials.value = false; } catch (error) { console.error('ä¿åé¢æå¤±è´¥:', error); ElMessage.error('ä¿åé¢æå¤±è´¥'); } finally { saving.value = false; } }; </script> <style scoped lang="scss"> .material-requisition-form { .el-table { margin-top: 10px; } } .dialog-footer { display: flex; justify-content: flex-end; gap: 10px; } :deep(.el-dialog) { height: 85vh; margin-top: 3vh !important; display: flex; flex-direction: column; } :deep(.el-dialog__body) { flex: 1; overflow-y: auto; padding: 15px 20px; } :deep(.el-dialog__header) { padding: 15px 20px; border-bottom: 1px solid #e4e7ed; } :deep(.el-dialog__footer) { padding: 15px 20px; border-top: 1px solid #e4e7ed; } </style> src/views/productionManagement/productionOrder/index.vue
@@ -102,6 +102,12 @@ :order-data="currentOrderData" @save="handleSaveClearanceRecord" /> <!-- é¢æå¼¹æ¡ --> <material-requisition-dialog v-model="materialRequisitionVisible" :order-data="currentOrderData" /> </div> </template> @@ -123,6 +129,7 @@ const NewProductOrder = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/New.vue")); const ClearanceRecordDialog = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/ClearanceRecordDialog.vue")); const MaterialRequisitionDialog = defineAsyncComponent(() => import("@/views/productionManagement/productionOrder/MaterialRequisitionDialog.vue")); const {proxy} = getCurrentInstance(); @@ -244,6 +251,14 @@ handleClearanceRecord(row); }, }, { name: "颿", type: "text", showHide: row => !row.isEnd, clickFun: row => { handleMaterialRequisition(row); }, }, ], }, ]); @@ -310,6 +325,9 @@ // æ¸ åºè®°å½å¼¹æ¡ const clearanceDialogVisible = ref(false); const currentOrderData = ref({}); // é¢æå¼¹æ¡ const materialRequisitionVisible = ref(false); const bindForm = reactive({ orderId: null, routeId: null, @@ -525,6 +543,13 @@ proxy.$modal.msgError("æ¸ åºè®°å½ä¿å失败"); } }; // æå¼é¢æå¼¹æ¡ const handleMaterialRequisition = (row) => { currentOrderData.value = row; materialRequisitionVisible.value = true; }; onMounted(() => { getList(); }); src/views/salesManagement/salesLedger/index.vue
@@ -46,6 +46,7 @@ <el-table-column align="center" label="åºå·" type="index"/> <el-table-column label="产å大类" prop="productCategory" /> <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> <el-table-column label="æ¹å·" prop="batchNo" /> <el-table-column label="åä½" prop="unit" /> <el-table-column label="产åç¶æ" width="100px" @@ -124,6 +125,7 @@ <el-button link type="primary" size="small" @click="openForm('edit', scope.row)" :disabled="!scope.row.isEdit">ç¼è¾</el-button> <!-- <el-button link type="primary" size="small" @click="openForm('view', scope.row)">详æ </el-button>--> <el-button link type="primary" size="small" @click="downLoadFile(scope.row)">éä»¶</el-button> <el-button link type="primary" size="small" @click="exportSaleOutbound(scope.row)">æå°éå®åºåºå</el-button> <!-- <el-button link type="primary" size="small" @click="openDeliveryForm(scope.row)">åè´§</el-button>--> </template> </el-table-column> @@ -228,6 +230,7 @@ <el-table-column label="产å大类" prop="productCategory" /> <el-table-column label="è§æ ¼åå·" prop="specificationModel" /> <el-table-column label="UIDç " prop="uidNo" /> <el-table-column label="æ¹å·" prop="batchNo" /> <el-table-column label="åä½" prop="unit" /> <el-table-column label="æ°é" prop="quantity" /> <el-table-column label="ç¨ç(%)" prop="taxRate" /> @@ -362,6 +365,15 @@ </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="24"> <el-form-item label="æ¹å·ï¼" prop="batchNo"> <el-select v-model="productForm.batchNo" placeholder="è¯·éæ©" clearable filterable> <el-option v-for="item in batchNoOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="åä½ï¼" prop="unit"> @@ -667,20 +679,22 @@ import FormDialog from '@/components/Dialog/FormDialog.vue'; import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; import { ledgerListPage, productList, customerList, addOrUpdateSalesLedger, getSalesLedgerWithProducts, delLedger, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInventory, ledgerListPage, productList, customerList, addOrUpdateSalesLedger, getSalesLedgerWithProducts, delLedger, addOrUpdateSalesLedgerProduct, delProduct, delLedgerFile, getProductInventory, saleOutboundExport, } from "@/api/salesManagement/salesLedger.js"; import { modelList, productTreeList } from "@/api/basicData/product.js"; import useFormData from "@/hooks/useFormData.js"; import dayjs from "dayjs"; import { getCurrentDate } from "@/utils/index.js"; import {getProductOrderBatchNoOptions} from "@/api/productionManagement/productionOrder.js"; import {safeTrainingExport} from "@/api/safeProduction/safetyTrainingAssessment.js"; const userStore = useUserStore(); const { proxy } = getCurrentInstance(); @@ -748,10 +762,12 @@ taxInclusiveTotalPrice: "", taxExclusiveTotalPrice: "", invoiceType: "", batchNo: "", }, productRules: { productCategory: [{ required: true, message: "è¯·éæ©", trigger: "change" }], productModelId: [{ required: true, message: "è¯·éæ©", trigger: "change" }], batchNo: [{ required: true, message: "è¯·éæ©", trigger: "change" }], specificationModel: [ { required: true, message: "è¯·éæ©", trigger: "change" }, ], @@ -1245,6 +1261,12 @@ }); } }); }; const batchNoOptions = ref([]); const fetchBatchNoOptions = async () => { const res = await getProductOrderBatchNoOptions(); batchNoOptions.value = res.data; }; // å ³éå¼¹æ¡ const closeDia = () => { @@ -2183,8 +2205,41 @@ let res = await userStore.getInfo(); currentFactoryName.value = res.user.currentFactoryName; }; const exportSaleOutbound = row => { saleOutboundExport({id: row.id}) .then(res => { // å建Blob对象 const blob = new Blob([res], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", }); // å建ä¸è½½é¾æ¥ const url = window.URL.createObjectURL(blob); const link = document.createElement("a"); link.href = url; link.download = `éå®åºåºå.docx`; // 模æç¹å»ä¸è½½ document.body.appendChild(link); link.click(); // æ¸ ç临æ¶å¯¹è±¡ setTimeout(() => { document.body.removeChild(link); window.URL.revokeObjectURL(url); }, 100); ElMessage.success("å¯¼åºæå"); }) .catch(err => { console.error("导åºå¤±è´¥:", err); ElMessage.error("导åºå¤±è´¥ï¼è¯·éè¯"); }); }; onMounted(() => { getList(); fetchBatchNoOptions(); userListNoPage().then(res => { userList.value = res.data; })