Merge remote-tracking branch 'origin/dev_长治_健齿齿科器材' into dev_长治_健齿齿科器材
| | |
| | | url: "/stockInventory/getMaterials", |
| | | method: "get", |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // 获取库存树(产品->规格/型号->批号->供应商) |
| | | export const getStockInventoryAll = (params = {}) => { |
| | | return request({ |
| | | url: "/stockInventory/getStockInventoryAll", |
| | | method: "get", |
| | | params, |
| | | }); |
| | | }; |
| | |
| | | data: query, |
| | | }); |
| | | } |
| | | |
| | | // 下载返工附件 |
| | | export function downloadReturnRecord(id) { |
| | | return request({ |
| | | url: "/quality/qualityUnqualified/downloadReturnRecord", |
| | | method: "get", |
| | | params: { id }, |
| | | responseType: "blob", |
| | | }); |
| | | } |
| | |
| | | <div> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <el-button type="danger" plain @click="handleDelete">删除</el-button> |
| | | <el-button type="primary" plain @click="handlePrint">打印</el-button> |
| | | <!-- <el-button type="primary" plain @click="handlePrint">打印</el-button> --> |
| | | </div> |
| | | </div> |
| | | <div class="table_list"> |
| | |
| | | > |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column |
| | | <!-- <el-table-column |
| | | label="出库批次" |
| | | prop="outboundBatches" |
| | | min-width="100" |
| | | show-overflow-tooltip |
| | | /> |
| | | /> --> |
| | | <el-table-column |
| | | label="批号" |
| | | min-width="120" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="scope"> |
| | | {{ scope.row.batchNo || "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="供应商" |
| | | min-width="160" |
| | | show-overflow-tooltip |
| | | > |
| | | <template #default="scope"> |
| | | {{ scope.row.supplierName || scope.row.customer || "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="出库日期" |
| | | prop="createTime" |
| | |
| | | </div> |
| | | </div> |
| | | <div class="info-row"> |
| | | <span class="label">单号:</span> |
| | | <span class="value">${item.code || ''}</span> |
| | | <div> |
| | | <span class="label">批号:</span> |
| | | <span class="value">${item.batchNo || item.outboundBatches || ''}</span> |
| | | </div> |
| | | <div> |
| | | <span class="label">单号:</span> |
| | | <span class="value">${item.code || ''}</span> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | |
| | | label="序号" |
| | | type="index" |
| | | width="60"/> |
| | | <el-table-column label="入库批次" |
| | | <!-- <el-table-column label="入库批次" |
| | | prop="inboundBatches" |
| | | width="280" |
| | | show-overflow-tooltip/> |
| | | show-overflow-tooltip/> --> |
| | | <el-table-column label="批号" |
| | | min-width="160" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.batchNo || '' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="供应商" |
| | | min-width="200" |
| | | show-overflow-tooltip> |
| | | <template #default="scope"> |
| | | {{ scope.row.supplierName || scope.row.customer || '' }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="入库时间" |
| | | prop="createTime" |
| | | show-overflow-tooltip/> |
| | |
| | | <el-input v-model="formState.unit" disabled /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="批号" prop="batchNo" :rules="[{ required: true, message: '请输入批号', trigger: 'blur' }]"> |
| | | <el-input v-model="formState.batchNo" placeholder="请输入批号" clearable /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="供应商" |
| | | prop="customer" |
| | | :rules="[{ required: true, message: '请选择供应商', trigger: 'change' }]" |
| | | > |
| | | <el-select |
| | | v-model="formState.customer" |
| | | placeholder="请选择供应商" |
| | | filterable |
| | | clearable |
| | | allow-create |
| | | :reserve-keyword="true" |
| | | :default-first-option="false" |
| | | > |
| | | <el-option |
| | | v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.supplierName" |
| | | > |
| | | {{ item.supplierName}} |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="库存数量" |
| | | prop="qualitity" |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, computed, getCurrentInstance} from "vue"; |
| | | import {ref, computed, getCurrentInstance, watch} from "vue"; |
| | | import ProductSelectDialog from "@/views/basicData/product/ProductSelectDialog.vue"; |
| | | import {createStockInventory} from "@/api/inventoryManagement/stockInventory.js"; |
| | | import {createStockUnInventory} from "@/api/inventoryManagement/stockUninventory.js"; |
| | | import {getOptions as getSupplierOptions} from "@/api/procurementManagement/procurementLedger.js"; |
| | | |
| | | const props = defineProps({ |
| | | visible: { |
| | |
| | | productName: "", |
| | | productModelName: "", |
| | | unit: "", |
| | | batchNo: "", |
| | | customer: "", |
| | | qualitity: 0, |
| | | warnNum: 0, |
| | | remark: '', |
| | |
| | | productModelId: undefined, |
| | | productName: "", |
| | | productModelName: "", |
| | | description: '', |
| | | unit: "", |
| | | batchNo: "", |
| | | customer: "", |
| | | qualitity: 0, |
| | | warnNum: 0, |
| | | remark: '', |
| | | }; |
| | | isShow.value = false; |
| | | }; |
| | | |
| | | const supplierList = ref([]); |
| | | |
| | | const loadSuppliers = async () => { |
| | | try { |
| | | const res = await getSupplierOptions(); |
| | | // 复用采购台账筛选逻辑:isWhite=0 的供应商 |
| | | supplierList.value = (res?.data || []).filter(item => item.isWhite === 0); |
| | | } catch (e) { |
| | | console.error("获取供应商列表失败:", e); |
| | | supplierList.value = []; |
| | | } |
| | | }; |
| | | |
| | | watch( |
| | | () => props.visible, |
| | | (val) => { |
| | | if (val) { |
| | | loadSuppliers(); |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | // 产品选择处理 |
| | | const handleProductSelect = async (products) => { |
| | | if (products && products.length > 0) { |
| | |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">产品大类:</span> |
| | | <span class="search_title ml10">产品类型:</span> |
| | | <el-radio-group v-model="productScope" class="qualified-product-scope" @change="onProductScopeChange"> |
| | | <el-radio-button label="成品">成品</el-radio-button> |
| | | <el-radio-button label="其他产品">其他产品</el-radio-button> |
| | | </el-radio-group> |
| | | <!-- <span class="search_title ml10" style="margin-left: 20px">产品大类:</span> |
| | | <el-input v-model="searchForm.productName" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> --> |
| | | <span class="search_title ml10" style="margin-left: 20px">规格型号:</span> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <span class="search_title ml10" style="margin-left: 20px">UID码:</span> |
| | | <el-input v-model="searchForm.uidNo" |
| | | style="width: 200px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <span class="search_title ml10" style="margin-left: 20px">批次号:</span> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 200px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button> |
| | |
| | | <el-table-column label="产品大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="规格型号" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="UID码" prop="uidNo" show-overflow-tooltip /> |
| | | <el-table-column label="批号" prop="batchNo" show-overflow-tooltip /> |
| | | <el-table-column label="供应商" prop="customer" show-overflow-tooltip /> |
| | | <el-table-column label="单位" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="库存数量" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip /> |
| | |
| | | |
| | | <script setup> |
| | | import pagination from '@/components/PIMTable/Pagination.vue' |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance } from 'vue' |
| | | import { ref, reactive, toRefs, onMounted, getCurrentInstance, defineAsyncComponent } from 'vue' |
| | | import {ElMessage, ElMessageBox} from "element-plus"; |
| | | import { getStockInventoryListPage } from "@/api/inventoryManagement/stockInventory.js"; |
| | | const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue")); |
| | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: '', |
| | | model: '', |
| | | uidNo: '', |
| | | batchNo: '', |
| | | } |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | | |
| | | // 成品(2) / 其他产品(原材料1、半成品3),与产品类型字典一致;分页接口需支持 productType 或 productTypes |
| | | const productScope = ref('成品') |
| | | |
| | | const getProductScopeParams = () => { |
| | | if (productScope.value === '成品') { |
| | | return { productType: 2 } |
| | | } |
| | | return { productTypes: '1,3' } |
| | | } |
| | | |
| | | const onProductScopeChange = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | |
| | | } |
| | | const getList = () => { |
| | | tableLoading.value = true |
| | | getStockInventoryListPage({ ...searchForm.value, ...page }).then(res => { |
| | | getStockInventoryListPage({ ...searchForm.value, ...page, ...getProductScopeParams() }).then(res => { |
| | | tableLoading.value = false |
| | | tableData.value = res.data.records |
| | | total.value = res.data.total |
| | |
| | | type: 'warning', |
| | | } |
| | | ).then(() => { |
| | | proxy.download("/stockInventory/exportStockInventory", {}, '合格库存信息.xlsx') |
| | | proxy.download("/stockInventory/exportStockInventory", { ...searchForm.value, ...getProductScopeParams() }, '合格库存信息.xlsx') |
| | | }).catch(() => { |
| | | proxy.$modal.msg("已取消") |
| | | }) |
| | |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .qualified-product-scope { |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <span class="search_title ml10" style="margin-left: 20px">规格型号:</span> |
| | | <el-input v-model="searchForm.model" |
| | | style="width: 240px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <span class="search_title ml10" style="margin-left: 20px">UID码:</span> |
| | | <el-input v-model="searchForm.uidNo" |
| | | style="width: 200px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <span class="search_title ml10" style="margin-left: 20px">批次号:</span> |
| | | <el-input v-model="searchForm.batchNo" |
| | | style="width: 200px" |
| | | placeholder="请输入" |
| | | clearable/> |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button> |
| | | </div> |
| | | <div> |
| | |
| | | <el-table-column label="产品大类" prop="productName" show-overflow-tooltip /> |
| | | <el-table-column label="规格型号" prop="model" show-overflow-tooltip /> |
| | | <el-table-column label="UID码" prop="uidNo" show-overflow-tooltip /> |
| | | <el-table-column label="批号" prop="batchNo" show-overflow-tooltip /> |
| | | <el-table-column label="供应商" prop="customer" show-overflow-tooltip /> |
| | | <el-table-column label="单位" prop="unit" show-overflow-tooltip /> |
| | | <el-table-column label="库存数量" prop="qualitity" show-overflow-tooltip /> |
| | | <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip /> |
| | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | productName: '', |
| | | model: '', |
| | | uidNo: '', |
| | | batchNo: '', |
| | | } |
| | | }) |
| | | const { searchForm } = toRefs(data) |
| | |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="入库批次" |
| | | prop="inboundBatches" |
| | | width="240" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | /> |
| | | <el-table-column |
| | | label="批号" |
| | | width="240" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | > |
| | | <template #default="scope"> |
| | | {{ scope.row.batchNo || scope.row.inboundBatches || "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="供应商" |
| | | prop="supplierName" |
| | | min-width="200" |
| | | show-overflow-tooltip |
| | | v-if="searchForm.reportType !== 'inout'" |
| | | > |
| | | <template #default="scope"> |
| | | {{ scope.row.supplierName || scope.row.customer || "" }} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column |
| | | label="产品大类" |
| | | prop="productName" |
| | |
| | | prop="productCategory" /> |
| | | <el-table-column label="规格型号" |
| | | prop="specificationModel" /> |
| | | <el-table-column label="UID码" prop="uidNo" /> |
| | | <el-table-column label="单位" |
| | | prop="unit" /> |
| | | <el-table-column label="数量" |
| | |
| | | prop="supplierName" |
| | | width="160" |
| | | show-overflow-tooltip /> |
| | | <el-table-column label="项目名称" |
| | | <!-- <el-table-column label="项目名称" |
| | | prop="projectName" |
| | | width="320" |
| | | show-overflow-tooltip /> |
| | | show-overflow-tooltip /> --> |
| | | <el-table-column label="审批状态" |
| | | prop="approvalStatus" |
| | | width="100" |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项目名称" |
| | | prop="projectName"> |
| | | <el-input v-model="form.projectName" |
| | | placeholder="请输入" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="付款方式"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请输入" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="签订日期:" |
| | | prop="executionDate"> |
| | | <el-date-picker style="width: 100%" |
| | |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <!-- <el-col :span="12"> |
| | | <el-form-item label="项目名称" |
| | | prop="projectName"> |
| | | <el-input v-model="form.projectName" |
| | | placeholder="请输入" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> --> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <!-- <el-col :span="12"> |
| | | <el-form-item label="付款方式"> |
| | | <el-input v-model="form.paymentMethod" |
| | | placeholder="请输入" |
| | | clearable /> |
| | | </el-form-item> |
| | | </el-col> --> |
| | | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | prop="unit" |
| | | width="70" /> |
| | | <el-table-column label="UID码" prop="uidNo" /> |
| | | <el-table-column label="批次号" prop="batchNo" /> |
| | | <el-table-column label="数量" |
| | | prop="quantity" |
| | | width="70" /> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="批次号:" |
| | | prop="batchNo"> |
| | | <el-input v-model="productForm.batchNo" |
| | | placeholder="请输入" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="单位:" |
| | |
| | | productCategory: "", |
| | | productModelId: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | specificationModel: "", |
| | | unit: "", |
| | | quantity: "", |
| | |
| | | productRules: { |
| | | productId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | productModelId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | batchNo: [{ required: true, message: "请输入批次号", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | taxInclusiveUnitPrice: [ |
| | |
| | | <el-dialog |
| | | v-model="visible" |
| | | title="领料" |
| | | width="1000px" |
| | | width="1400px" |
| | | top="3vh" |
| | | :close-on-click-modal="false" |
| | | destroy-on-close |
| | |
| | | <el-table-column prop="productName" label="产品名称" min-width="150" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <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="customer" label="供应商" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column prop="batchNo" label="批号" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="requisitionQty" label="领用数量" width="120" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-input-number |
| | |
| | | <el-dialog |
| | | v-model="addDialogVisible" |
| | | title="选择原材料" |
| | | width="800px" |
| | | width="1000px" |
| | | top="5vh" |
| | | :close-on-click-modal="false" |
| | | append-to-body |
| | | > |
| | | <div class="material-filter" style="margin-bottom: 20px;"> |
| | | <el-select |
| | | v-model="filterSupplier" |
| | | placeholder="供应商" |
| | | clearable |
| | | filterable |
| | | style="width: 220px" |
| | | > |
| | | <el-option |
| | | v-for="opt in supplierFilterOptions" |
| | | :key="opt" |
| | | :label="opt" |
| | | :value="opt" |
| | | /> |
| | | </el-select> |
| | | <el-select |
| | | v-model="filterBatchNo" |
| | | placeholder="批号" |
| | | clearable |
| | | filterable |
| | | style="width: 220px; margin-left: 12px" |
| | | > |
| | | <el-option |
| | | v-for="opt in batchFilterOptions" |
| | | :key="opt" |
| | | :label="opt" |
| | | :value="opt" |
| | | /> |
| | | </el-select> |
| | | </div> |
| | | <el-table |
| | | :data="availableMaterials" |
| | | :data="filteredMaterials" |
| | | border |
| | | style="width: 100%" |
| | | height="50vh" |
| | |
| | | <el-table-column prop="productName" label="产品名称" min-width="150" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <el-table-column prop="unit" label="单位" width="80" align="center" /> |
| | | <el-table-column prop="customer" label="供应商" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column prop="batchNo" label="批号" min-width="180" show-overflow-tooltip /> |
| | | <!-- <el-table-column prop="qualitity" label="可领用数量" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | {{ row.qualitity || 0 }} |
| | |
| | | const availableMaterials = ref([]); |
| | | const selectedMaterials = ref([]); |
| | | |
| | | // 选择弹窗筛选条件(供应商/批号) |
| | | const filterSupplier = ref(''); |
| | | const filterBatchNo = ref(''); |
| | | |
| | | // 将后端可能返回的字段做一下归一化:供应商/批号字段名可能不一致 |
| | | const normalizeMaterial = (m) => { |
| | | return { |
| | | ...m, |
| | | customer: m.customer ?? m.supplierName ?? '', |
| | | batchNo: m.batchNo ?? m.batchNumber ?? m.batch_number ?? m.lotNo ?? '', |
| | | }; |
| | | }; |
| | | |
| | | const supplierFilterOptions = computed(() => { |
| | | return Array.from(new Set(availableMaterials.value.map((m) => m.customer).filter(Boolean))); |
| | | }); |
| | | |
| | | const batchFilterOptions = computed(() => { |
| | | const list = filterSupplier.value |
| | | ? availableMaterials.value.filter((m) => m.customer === filterSupplier.value) |
| | | : availableMaterials.value; |
| | | return Array.from(new Set(list.map((m) => m.batchNo).filter(Boolean))); |
| | | }); |
| | | |
| | | const filteredMaterials = computed(() => { |
| | | return availableMaterials.value.filter((m) => { |
| | | if (filterSupplier.value && m.customer !== filterSupplier.value) return false; |
| | | if (filterBatchNo.value && m.batchNo !== filterBatchNo.value) return false; |
| | | return true; |
| | | }); |
| | | }); |
| | | |
| | | watch(filterSupplier, () => { |
| | | // 如果当前“批号”不属于所选供应商,则清空 |
| | | if (filterBatchNo.value && !batchFilterOptions.value.includes(filterBatchNo.value)) { |
| | | filterBatchNo.value = ''; |
| | | } |
| | | }); |
| | | |
| | | // 监听弹框打开,加载数据 |
| | | watch(() => props.modelValue, (val) => { |
| | | if (val && props.orderData) { |
| | |
| | | if (bomId) { |
| | | try { |
| | | const res = await getMaterials({ bomId }); |
| | | materialsFromApi = res.data || []; |
| | | materialsFromApi = (res.data || []).map(normalizeMaterial); |
| | | } catch (error) { |
| | | console.error('查询原材料列表失败:', error); |
| | | } |
| | |
| | | return { |
| | | ...savedItem, |
| | | qualitity: apiItem?.qualitity ?? savedItem.qualitity ?? 0, |
| | | requisitionQty: savedItem.requisitionQty || 0 |
| | | requisitionQty: savedItem.requisitionQty || 0, |
| | | customer: savedItem.customer ?? savedItem.supplierName ?? apiItem?.customer ?? '', |
| | | batchNo: savedItem.batchNo ?? savedItem.batchNumber ?? apiItem?.batchNo ?? '', |
| | | }; |
| | | }); |
| | | } catch (e) { |
| | |
| | | const res = await getMaterials({ bomId }); |
| | | console.log('getMaterials返回数据:', res.data); |
| | | // 直接展示所有数据,不过滤 |
| | | availableMaterials.value = res.data || []; |
| | | availableMaterials.value = (res.data || []).map(normalizeMaterial); |
| | | filterSupplier.value = ''; |
| | | filterBatchNo.value = ''; |
| | | selectedMaterials.value = []; |
| | | addDialogVisible.value = true; |
| | | } catch (error) { |
| | |
| | | .map(item => ({ |
| | | ...item, |
| | | requisitionQty: 0, |
| | | remark: '' |
| | | remark: '', |
| | | })); |
| | | |
| | | if (newItems.length === 0) { |
| | |
| | | visible.value = false; |
| | | materialList.value = []; |
| | | activeTab.value = 'material'; |
| | | emit('confirm'); |
| | | } catch (error) { |
| | | console.error('保存领料失败:', error); |
| | | ElMessage.error('保存领料失败'); |
| | |
| | | const product = products[0]; |
| | | formState.value.productId = product.productId; |
| | | formState.value.productName = product.productName; |
| | | const productNameArr = product.productName.split('-'); |
| | | if (productNameArr.length === 3 && productNameArr[0] && productNameArr[1] !== '') { |
| | | formState.value.manufacturingTeam = productNameArr[1].charAt(0) + '类车间'; |
| | | } |
| | | formState.value.manufacturingTeam = product.parentName.charAt(0) + '类车间'; |
| | | |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | |
| | | <material-requisition-dialog |
| | | v-model="materialRequisitionVisible" |
| | | :order-data="currentOrderData" |
| | | @confirm="handleQuery" |
| | | /> |
| | | </div> |
| | | </template> |
| | |
| | | width: '120px', |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: '120px', |
| | | }, |
| | | { |
| | | label: "工艺路线编号", |
| | | prop: "processRouteCode", |
| | | width: '200px', |
| | |
| | | prop: 'uidNo', |
| | | }, |
| | | { |
| | | label: '供应商', |
| | | prop: 'customer', |
| | | }, |
| | | { |
| | | label: '批号', |
| | | prop: 'batchNo', |
| | | }, |
| | | { |
| | | label: '投入数量', |
| | | prop: 'quantity', |
| | | }, |
| | |
| | | label-width="120px"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="产品名称"> |
| | | <el-input v-model="reportForm.productName" |
| | | readonly |
| | | style="width: 300px" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="待生产数量"> |
| | | <el-input v-model="reportForm.planQuantity" |
| | | readonly |
| | |
| | | @input="handleScrapQtyInput" /> |
| | | </el-form-item></el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检品数量" |
| | | prop="inspectedQuantity"> |
| | | <el-input v-model.number="reportForm.inspectedQuantity" |
| | | type="number" |
| | | min="0" |
| | | step="1" |
| | | style="width: 300px" |
| | | placeholder="请输入检品数量" |
| | | @input="handleInspectedQuantity"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="班组信息"> |
| | | <el-select v-model="reportForm.userId" |
| | | style="width: 300px" |
| | |
| | | <el-table-column prop="productName" label="产品名称" min-width="160" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <el-table-column prop="unit" label="单位" width="90" align="center" /> |
| | | <el-table-column prop="customer" label="供应商" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column prop="batchNo" label="批号" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="reportQty" label="领用数量" width="160" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-input-number |
| | |
| | | :min="0" |
| | | :precision="2" |
| | | :controls="false" |
| | | :max="row.qualitity || 0" |
| | | :disabled="!row.qualitity" |
| | | :max="row.requisitionQty || 0" |
| | | :disabled="!row.requisitionQty" |
| | | style="width: 100%" |
| | | /> |
| | | </template> |
| | |
| | | <el-dialog |
| | | v-model="addMaterialDialogVisible" |
| | | title="选择原材料" |
| | | width="1000px" |
| | | width="1400px" |
| | | top="5vh" |
| | | :close-on-click-modal="false" |
| | | append-to-body |
| | |
| | | <el-table-column prop="productName" label="产品名称" min-width="160" /> |
| | | <el-table-column prop="model" label="型号" min-width="150" /> |
| | | <el-table-column prop="unit" label="单位" width="90" align="center" /> |
| | | <el-table-column prop="qualitity" label="可领用数量" width="140" align="center" /> |
| | | <el-table-column prop="customer" label="供应商" min-width="160" show-overflow-tooltip /> |
| | | <el-table-column prop="batchNo" label="批号" min-width="180" show-overflow-tooltip /> |
| | | <el-table-column prop="requisitionQty" label="可领用数量" width="140" align="center" /> |
| | | </el-table> |
| | | |
| | | <!-- 已选择明细展示放在报工弹框下方的 reportForm.drawMaterialList 表格里 --> |
| | |
| | | const userOptions = ref([]); |
| | | const deviceOptions = ref([]); |
| | | const reportForm = reactive({ |
| | | // 报工弹框里“产品名称”只读回显 |
| | | productName: "", |
| | | planQuantity: 0, |
| | | totalInvestment: 0, |
| | | quantity: null, |
| | |
| | | const showReportDialog = async row => { |
| | | currentReportRowData.value = row; |
| | | processParamList.value = await getProcessParamList(row) |
| | | // 兼容后端/表格字段命名:优先 row.productName,其次 row.productCategory |
| | | reportForm.productName = row.productName ?? row.productCategory ?? '' |
| | | reportForm.planQuantity = row.planQuantity; |
| | | reportForm.totalInvestment = row.totalInvestment; |
| | | reportForm.quantity = |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="单位:" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请输入" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="批号:" prop="batchNo"> |
| | | <el-input |
| | | v-model="form.batchNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="operationType === 'edit'" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="UID码:" prop="uidNo"> |
| | | <el-input v-model="form.uidNo" placeholder="请输入" disabled/> |
| | | </el-form-item> |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="单位:" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请输入" disabled/> |
| | | <el-form-item label="检品数量:" prop="inspectedQuantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.inspectedQuantity" placeholder="请输入" clearable :precision="2"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="quantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | |
| | | const validateBatchNo = (rule, value, callback) => { |
| | | if (value === undefined || value === null || String(value).trim() === '') { |
| | | callback(new Error('请输入批号')); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkTime: "", |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | inspectedQuantity: "", |
| | | quantity: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | |
| | | productModelId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | testStandardId: [{required: false, message: "请选择指标", trigger: "change"}], |
| | | unit: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | inspectedQuantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | inspectedQuantity: [ |
| | | { required: true, message: "请输入检品数量", trigger: "blur" }, |
| | |
| | | } |
| | | ], |
| | | checkCompany: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请输入", trigger: "change" }], |
| | | }, |
| | | }); |
| | |
| | | form.value.productModelId = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.uidNo = undefined; |
| | | form.value.batchNo = ""; |
| | | modelOptions.value = []; |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="批号:" prop="batchNo" :required="operationType === 'add'"> |
| | | <el-input |
| | | v-model="form.batchNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="operationType === 'edit'" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="单位:" prop="unit"> |
| | | <el-input v-model="form.unit" placeholder="请输入" disabled/> |
| | | </el-form-item> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, toRefs} from "vue"; |
| | | import {ref, reactive, toRefs, getCurrentInstance} from "vue"; |
| | | import {modelList, productTreeList} from "@/api/basicData/product.js"; |
| | | import { |
| | | getQualityUnqualifiedInfo, |
| | |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | |
| | | const validateBatchNo = (rule, value, callback) => { |
| | | if (operationType.value !== 'add') { |
| | | callback(); |
| | | return; |
| | | } |
| | | if (value === undefined || value === null || String(value).trim() === '') { |
| | | callback(new Error('请输入批号')); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const { rejection_handling } = proxy.useDict("rejection_handling") |
| | | const data = reactive({ |
| | | form: { |
| | |
| | | productId: "", |
| | | model: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | checkCompany: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | checkResult: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | dealName: [{ required: true, message: "请选择处理人", trigger: "change" }], |
| | | batchNo: [{ validator: validateBatchNo, trigger: "blur" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | |
| | | productId: '', |
| | | model: '', |
| | | uidNo: '', |
| | | batchNo: '', |
| | | unit: '', |
| | | quantity: '', |
| | | productName: '', |
| | |
| | | form.value.model = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.uidNo = undefined; |
| | | form.value.batchNo = ""; |
| | | modelOptions.value = []; |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | | modelList({ id: value }).then((res) => { |
| | |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="批号:" prop="batchNo"> |
| | | <el-input v-model="form.batchNo" placeholder="—" disabled /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验员:" prop="checkName"> |
| | | <el-input v-model="form.checkName" placeholder="请输入" clearable disabled/> |
| | | </el-form-item> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref, reactive, toRefs, computed} from "vue"; |
| | | import {ref, reactive, toRefs, computed, getCurrentInstance} from "vue"; |
| | | import {productTreeList} from "@/api/basicData/product.js"; |
| | | import { |
| | | getQualityUnqualifiedInfo, |
| | |
| | | productName: "", |
| | | productId: "", |
| | | model: "", |
| | | batchNo: "", |
| | | unit: "", |
| | | quantity: "", |
| | | checkCompany: "", |
| | |
| | | import {onMounted, ref, reactive, toRefs, nextTick, getCurrentInstance} from "vue"; |
| | | import FormDia from "@/views/qualityManagement/nonconformingManagement/components/formDia.vue"; |
| | | import {ElMessageBox} from "element-plus"; |
| | | import {qualityUnqualifiedDel, qualityUnqualifiedListPage} from "@/api/qualityManagement/nonconformingManagement.js"; |
| | | import {qualityUnqualifiedDel, qualityUnqualifiedListPage, downloadReturnRecord} from "@/api/qualityManagement/nonconformingManagement.js"; |
| | | import InspectionFormDia from "@/views/qualityManagement/nonconformingManagement/components/inspectionFormDia.vue"; |
| | | import dayjs from "dayjs"; |
| | | |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | label: "操作", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 100, |
| | | width: 180, |
| | | operation: [ |
| | | { |
| | | name: "处理", |
| | |
| | | openInspectionForm("edit", row); |
| | | }, |
| | | disabled: (row) => row.inspectState === 1, |
| | | }, |
| | | { |
| | | name: "下载返工附件", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | handleDownloadReturnRecord(row); |
| | | }, |
| | | show: (row) => row.dealResult === "返工", |
| | | }, |
| | | ], |
| | | }, |
| | |
| | | }) |
| | | }; |
| | | |
| | | // 下载返工附件 |
| | | const handleDownloadReturnRecord = async (row) => { |
| | | try { |
| | | const blobData = await downloadReturnRecord(row.id); |
| | | |
| | | // 构建 Blob |
| | | const blob = new Blob([blobData], { |
| | | type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document" |
| | | }); |
| | | |
| | | // 下载 |
| | | const url = window.URL.createObjectURL(blob); |
| | | const link = document.createElement("a"); |
| | | link.href = url; |
| | | link.download = `返工附件.docx`; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | window.URL.revokeObjectURL(url); |
| | | |
| | | proxy.$modal.msgSuccess("下载成功"); |
| | | } catch (error) { |
| | | console.error("下载返工附件失败:", error); |
| | | proxy.$modal.msgError("下载失败"); |
| | | } |
| | | }; |
| | | |
| | | // 删除 |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="批号:" prop="batchNo"> |
| | | <el-input |
| | | v-model="form.batchNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="operationType === 'edit'" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检测单位:" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请输入" clearable/> |
| | | </el-form-item> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验员:" prop="checkName"> |
| | | <el-select v-model="form.checkName" placeholder="请选择" clearable> |
| | |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | |
| | | const validateBatchNo = (rule, value, callback) => { |
| | | if (value === undefined || value === null || String(value).trim() === '') { |
| | | callback(new Error('请输入批号')); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkTime: "", |
| | |
| | | productModelId: "", |
| | | model: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | |
| | | } |
| | | ], |
| | | checkCompany: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请输入", trigger: "change" }], |
| | | }, |
| | | }); |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | quantity: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | |
| | | form.value.productModelId = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.uidNo = undefined; |
| | | form.value.batchNo = ""; |
| | | modelOptions.value = []; |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检测单位:" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请输入" clearable/> |
| | | <el-form-item label="批号:" prop="batchNo"> |
| | | <el-input |
| | | v-model="form.batchNo" |
| | | placeholder="请输入" |
| | | clearable |
| | | :disabled="operationType === 'edit'" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检测单位:" prop="checkCompany"> |
| | | <el-input v-model="form.checkCompany" placeholder="请输入" clearable/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检测结果:" prop="checkResult"> |
| | | <el-select v-model="form.checkResult"> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验员:" prop="checkName"> |
| | | <el-select v-model="form.checkName" placeholder="请选择" clearable style="width: 100%"> |
| | |
| | | |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | |
| | | const validateBatchNo = (rule, value, callback) => { |
| | | if (value === undefined || value === null || String(value).trim() === '') { |
| | | callback(new Error('请输入批号')); |
| | | return; |
| | | } |
| | | callback(); |
| | | }; |
| | | |
| | | const data = reactive({ |
| | | form: { |
| | | checkTime: "", |
| | |
| | | productModelId: "", |
| | | model: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | |
| | | } |
| | | ], |
| | | checkCompany: [{required: false, message: "请输入", trigger: "blur"}], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{required: true, message: "请选择检测结果", trigger: "change"}], |
| | | }, |
| | | }); |
| | |
| | | productModelId: "", |
| | | model: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | |
| | | form.value.productModelId = undefined; |
| | | form.value.unit = undefined; |
| | | form.value.uidNo = undefined; |
| | | form.value.batchNo = ""; |
| | | modelOptions.value = []; |
| | | currentProductId.value = value |
| | | form.value.productName = findNodeById(productOptions.value, value); |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | { label: "销售单号", prop: "salesContractNo", minWidth: 160 }, |
| | | { label: "业务员", prop: "salesman", minWidth: 120 }, |
| | | { label: "关联出库单号", prop: "shippingNo", minWidth: 170 }, |
| | | { label: "项目名称", prop: "projectName", minWidth: 180 }, |
| | | // { label: "项目名称", prop: "projectName", minWidth: 180 }, |
| | | { label: "项目阶段", prop: "projectStage", minWidth: 120 }, |
| | | { label: "制单人", prop: "maker", minWidth: 120 }, |
| | | { label: "结算人", prop: "settler", minWidth: 120 }, |
| | |
| | | <el-table-column label="产品大类" prop="productCategory" /> |
| | | <el-table-column label="规格型号" prop="specificationModel" /> |
| | | <el-table-column label="批号" prop="batchNo" /> |
| | | <el-table-column label="UID码" prop="uidNo" /> |
| | | <el-table-column label="单位" prop="unit" /> |
| | | <el-table-column label="产品状态" |
| | | width="100px" |
| | |
| | | <el-table-column label="销售合同号" prop="salesContractNo" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="客户名称" prop="customerName" width="300" show-overflow-tooltip /> |
| | | <el-table-column label="业务员" prop="salesman" width="100" show-overflow-tooltip /> |
| | | <el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip /> |
| | | <!-- <el-table-column label="项目名称" prop="projectName" width="180" show-overflow-tooltip /> |
| | | <el-table-column label="付款方式" prop="paymentMethod" show-overflow-tooltip /> --> |
| | | <el-table-column label="合同金额(元)" prop="contractAmount" width="220" show-overflow-tooltip |
| | | :formatter="formattedNumber" /> |
| | | <el-table-column label="录入人" prop="entryPersonName" width="100" show-overflow-tooltip /> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="项目名称:" prop="projectName"> |
| | | <el-input v-model="form.projectName" placeholder="请输入" clearable :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="签订日期:" prop="executionDate"> |
| | | <el-date-picker style="width: 100%" v-model="form.executionDate" value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" type="date" placeholder="请选择" clearable :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="付款方式"> |
| | | <el-input v-model="form.paymentMethod" placeholder="请输入" clearable :disabled="operationType === 'view'" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="录入人:" prop="entryPerson"> |
| | |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="批号:" prop="batchNo"> |
| | | <el-select v-model="productForm.batchNo" placeholder="请选择" clearable filterable> |
| | | <el-select v-model="productForm.batchNo" |
| | | placeholder="请选择" |
| | | clearable |
| | | filterable |
| | | @change="handleBatchNoChange"> |
| | | <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="24"> |
| | | <el-form-item label="供应商:" prop="customer"> |
| | | <el-select v-model="productForm.customer" |
| | | placeholder="请选择" |
| | | clearable |
| | | filterable |
| | | :disabled="!supplierOptions.length"> |
| | | <el-option v-for="item in supplierOptions" :key="item.value" :label="item.label" :value="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <th>产品名称</th> |
| | | <th>规格型号</th> |
| | | <th>单位</th> |
| | | <th>UID码</th> |
| | | <th>单价</th> |
| | | <th>零售数量</th> |
| | | <th>零售金额</th> |
| | |
| | | <td>{{ product.productCategory || '' }}</td> |
| | | <td>{{ product.specificationModel || '' }}</td> |
| | | <td>{{ product.unit || '' }}</td> |
| | | <td>{{ product.uidNo || '' }}</td> |
| | | <td>{{ product.taxInclusiveUnitPrice || '0' }}</td> |
| | | <td>{{ product.quantity || '0' }}</td> |
| | | <td>{{ product.taxInclusiveTotalPrice || '0' }}</td> |
| | |
| | | delProduct, |
| | | delLedgerFile, getProductInventory, saleOutboundExport, |
| | | } from "@/api/salesManagement/salesLedger.js"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import { getStockInventoryAll } from "@/api/inventoryManagement/stockInventory.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import dayjs from "dayjs"; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | import {getProductOrderBatchNoOptions} from "@/api/productionManagement/productionOrder.js"; |
| | | // 由 /stockInventory/getStockInventoryAll 驱动“批号/供应商”联动 |
| | | import {safeTrainingExport} from "@/api/safeProduction/safetyTrainingAssessment.js"; |
| | | |
| | | const userStore = useUserStore(); |
| | |
| | | const customerOption = ref([]); |
| | | const productOptions = ref([]); |
| | | const modelOptions = ref([]); |
| | | const supplierOptions = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: 1, |
| | |
| | | const productFormData = reactive({ |
| | | productForm: { |
| | | productCategory: "", |
| | | customer: "", |
| | | specificationModel: "", |
| | | uidNo: "", |
| | | unit: "", |
| | |
| | | productCategory: [{ required: true, message: "请选择", trigger: "change" }], |
| | | productModelId: [{ required: true, message: "请选择", trigger: "change" }], |
| | | batchNo: [{ required: true, message: "请选择", trigger: "change" }], |
| | | customer: [{ required: true, message: "请选择", trigger: "change" }], |
| | | specificationModel: [ |
| | | { required: true, message: "请选择", trigger: "change" }, |
| | | ], |
| | |
| | | tableLoading.value = false; |
| | | }); |
| | | }; |
| | | // 获取产品大类tree数据 |
| | | const getProductOptions = () => { |
| | | let stockInventoryAllTree = []; |
| | | let batchNodeByBatchNo = new Map(); |
| | | |
| | | const normalizeStockInventoryTree = (nodes = []) => { |
| | | const normalizeNodeValue = (node) => { |
| | | // 后端有时会出现 id=null 的层级,这里给一个可用的 key |
| | | if (node?.id !== null && node?.id !== undefined) return String(node.id); |
| | | if (node?.nodeType === "batch") return String(node.batchNo ?? node.label ?? ""); |
| | | if (node?.nodeType === "customer") return String(node.customer ?? node.label ?? ""); |
| | | if (node?.nodeType === "model") return String(node.productModelId ?? node.model ?? node.label ?? ""); |
| | | return String(node.productName ?? node.label ?? ""); |
| | | }; |
| | | |
| | | const normalized = (list) => |
| | | (list || []).map((n) => { |
| | | const value = normalizeNodeValue(n); |
| | | const label = n.label ?? n.productName ?? n.model ?? n.batchNo ?? n.customer ?? ""; |
| | | return { |
| | | ...n, |
| | | value, |
| | | label, |
| | | children: normalized(n.children), |
| | | }; |
| | | }); |
| | | |
| | | return normalized(nodes); |
| | | }; |
| | | |
| | | // 仅展示最多 3 个层级:第 1 层(product) -> 第 2 层(model) -> 第 3 层(batch),更深的节点不展示 |
| | | const filterStockInventoryFirst3Levels = (nodes = []) => { |
| | | const MAX_LEVEL = 3; |
| | | |
| | | const cloneAndFilterByLevel = (list = [], level = 1) => { |
| | | return (list || []) |
| | | .map((n) => { |
| | | // 后续层级里如果还有 customer,直接剔除 |
| | | if (n.nodeType === "customer") return null; |
| | | |
| | | // 到达展示深度后,不再向下挂子节点 |
| | | if (level >= MAX_LEVEL) { |
| | | return { ...n, children: [] }; |
| | | } |
| | | |
| | | // 特例:batch 节点本身也不再展示 children(保持与接口节点语义一致) |
| | | if (n.nodeType === "batch") { |
| | | return { ...n, children: [] }; |
| | | } |
| | | |
| | | return { ...n, children: cloneAndFilterByLevel(n.children, level + 1) }; |
| | | }) |
| | | .filter(Boolean); |
| | | }; |
| | | |
| | | return cloneAndFilterByLevel(nodes, 1); |
| | | }; |
| | | |
| | | const findNodeObjByValue = (nodes = [], value) => { |
| | | for (let i = 0; i < (nodes || []).length; i++) { |
| | | const node = nodes[i]; |
| | | if (String(node?.value) === String(value)) return node; |
| | | const children = node?.children || []; |
| | | if (children.length) { |
| | | const found = findNodeObjByValue(children, value); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | // 获取库存树(用于产品大类/规格型号联动) |
| | | const getProductOptions = async () => { |
| | | // 返回 Promise,便于在编辑产品时等待加载完成 |
| | | return productTreeList().then((res) => { |
| | | productOptions.value = convertIdToValue(res); |
| | | return productOptions.value; |
| | | }); |
| | | const res = await getStockInventoryAll(); |
| | | const data = res?.data || []; |
| | | stockInventoryAllTree = normalizeStockInventoryTree(data); |
| | | productOptions.value = filterStockInventoryFirst3Levels(stockInventoryAllTree); |
| | | return productOptions.value; |
| | | }; |
| | | const formattedNumber = (row, column, cellValue) => { |
| | | return parseFloat(cellValue).toFixed(2); |
| | | }; |
| | | // 获取tree子数据 |
| | | // 获取tree子数据(先选产品,再选规格型号) |
| | | const getModels = (value) => { |
| | | productForm.value.productCategory = findNodeById(productOptions.value, value); |
| | | modelList({ id: value }).then((res) => { |
| | | modelOptions.value = res; |
| | | }); |
| | | const node = findNodeObjByValue(stockInventoryAllTree, value); |
| | | if (!node) return; |
| | | if (node.nodeType !== "product") return; |
| | | |
| | | // 选择产品后,重置下游字段 |
| | | productForm.value.productCategory = node.label; |
| | | modelOptions.value = (node.children || []) |
| | | .filter((c) => c.nodeType === "model") |
| | | .map((m) => ({ |
| | | id: m.value, |
| | | model: m.model ?? m.label ?? "", |
| | | unit: m.unit ?? "", |
| | | uidNo: m.uidNo ?? m.identifierCode ?? "", |
| | | })); |
| | | |
| | | productForm.value.productModelId = null; |
| | | productForm.value.specificationModel = ""; |
| | | productForm.value.uidNo = ""; |
| | | productForm.value.unit = ""; |
| | | productForm.value.batchNo = ""; |
| | | productForm.value.customer = ""; |
| | | productForm.value.taxInclusiveUnitPrice = ""; |
| | | productForm.value.taxInclusiveTotalPrice = ""; |
| | | productForm.value.taxExclusiveTotalPrice = ""; |
| | | |
| | | modelOptions.value = modelOptions.value || []; |
| | | batchNoOptions.value = []; |
| | | supplierOptions.value = []; |
| | | batchNodeByBatchNo = new Map(); |
| | | }; |
| | | |
| | | // 规格型号选择后:回显 UID,并生成“批号下拉” |
| | | const getProductModel = (value) => { |
| | | const index = modelOptions.value.findIndex((item) => item.id === value); |
| | | if (index !== -1) { |
| | | productForm.value.specificationModel = modelOptions.value[index].model; |
| | | productForm.value.unit = modelOptions.value[index].unit; |
| | | productForm.value.uidNo = modelOptions.value[index].uidNo || ""; |
| | | const modelNode = findNodeObjByValue(stockInventoryAllTree, value); |
| | | if (!modelNode || modelNode.nodeType !== "model") return; |
| | | |
| | | const prevBatchNo = productForm.value.batchNo; |
| | | const prevCustomer = productForm.value.customer; |
| | | |
| | | productForm.value.productModelId = modelNode.value; |
| | | productForm.value.specificationModel = modelNode.model ?? modelNode.label ?? ""; |
| | | // 有些接口/树数据里可能不包含 unit,这种情况下不要覆盖编辑时已回显的值 |
| | | const nextUnit = modelNode.unit ?? ""; |
| | | if (nextUnit !== null && nextUnit !== undefined && String(nextUnit).trim() !== "") { |
| | | productForm.value.unit = nextUnit; |
| | | } |
| | | // 有些接口/树数据里可能不包含 uidNo,这种情况下不要覆盖编辑时已回显的值 |
| | | const nextUidNo = modelNode.uidNo ?? modelNode.identifierCode ?? ""; |
| | | if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") { |
| | | productForm.value.uidNo = nextUidNo; |
| | | } |
| | | |
| | | const batchNodes = (modelNode.children || []).filter((b) => b.nodeType === "batch"); |
| | | batchNodeByBatchNo = new Map( |
| | | batchNodes.map((b) => { |
| | | const key = String(b.batchNo ?? b.value ?? b.label ?? "").trim(); |
| | | return [key, b]; |
| | | }) |
| | | ); |
| | | batchNoOptions.value = batchNodes.map((b) => ({ |
| | | label: String(b.batchNo ?? b.label ?? "").trim(), |
| | | value: String(b.batchNo ?? b.value ?? b.label ?? "").trim(), |
| | | })); |
| | | |
| | | // 批号不再属于新规格时,清空 |
| | | const batchValues = new Set(batchNoOptions.value.map((x) => x.value)); |
| | | if (!prevBatchNo || !batchValues.has(prevBatchNo)) { |
| | | productForm.value.batchNo = ""; |
| | | } |
| | | |
| | | // 需要供应商:批号回显后再生成 |
| | | productForm.value.customer = ""; |
| | | supplierOptions.value = []; |
| | | if (productForm.value.batchNo) { |
| | | handleBatchNoChange(productForm.value.batchNo, prevCustomer); |
| | | } |
| | | }; |
| | | |
| | | const handleBatchNoChange = (batchNo, prevCustomer) => { |
| | | const safeBatchNo = String(batchNo ?? "").trim(); |
| | | if (!safeBatchNo || !batchNodeByBatchNo.size) { |
| | | productForm.value.customer = ""; |
| | | supplierOptions.value = []; |
| | | return; |
| | | } |
| | | |
| | | const batchNode = batchNodeByBatchNo.get(String(safeBatchNo)); |
| | | if (!batchNode) { |
| | | productForm.value.customer = ""; |
| | | supplierOptions.value = []; |
| | | return; |
| | | } |
| | | |
| | | // UID码可能来源于 batch 节点(不同接口字段名不一致时尽量兜底) |
| | | const nextUidNo = batchNode.uidNo ?? batchNode.identifierCode ?? batchNode.uid ?? ""; |
| | | if (nextUidNo !== null && nextUidNo !== undefined && String(nextUidNo).trim() !== "") { |
| | | productForm.value.uidNo = nextUidNo; |
| | | } |
| | | |
| | | const customers = (batchNode.children || []) |
| | | .filter((c) => c.nodeType === "customer") |
| | | .map((c) => c.customer ?? c.label ?? "") |
| | | .filter(Boolean); |
| | | |
| | | const uniq = Array.from(new Set(customers)); |
| | | supplierOptions.value = uniq.map((s) => ({ label: s, value: s })); |
| | | |
| | | // 编辑场景尽量回显;新增场景不回显 |
| | | if (prevCustomer && uniq.includes(prevCustomer)) { |
| | | productForm.value.customer = prevCustomer; |
| | | } else { |
| | | productForm.value.specificationModel = null; |
| | | productForm.value.unit = null; |
| | | productForm.value.uidNo = null; |
| | | productForm.value.customer = ""; |
| | | } |
| | | }; |
| | | const findNodeById = (nodes, productId) => { |
| | | for (let i = 0; i < nodes.length; i++) { |
| | | if (nodes[i].value === productId) { |
| | | return nodes[i].label; // 找到节点,返回该节点 |
| | | } |
| | | if (nodes[i].children && nodes[i].children.length > 0) { |
| | | const foundNode = findNodeById(nodes[i].children, productId); |
| | | if (foundNode) { |
| | | return foundNode; // 在子节点中找到,返回该节点 |
| | | } |
| | | } |
| | | } |
| | | return null; // 没有找到节点,返回null |
| | | }; |
| | | function convertIdToValue(data) { |
| | | return data.map((item) => { |
| | | const { id, children, ...rest } = item; |
| | | const newItem = { |
| | | ...rest, |
| | | value: id, // 将 id 改为 value |
| | | }; |
| | | if (children && children.length > 0) { |
| | | newItem.children = convertIdToValue(children); |
| | | } |
| | | |
| | | return newItem; |
| | | }); |
| | | } |
| | | // 根据名称反查产品大类 id,便于仅存名称时的反显 |
| | | function findNodeIdByLabel(nodes, label) { |
| | | if (!label) return null; |
| | |
| | | return { |
| | | // 台账字段 |
| | | productCategory: p.product || p.productName || "", |
| | | productModelId: p.productModelId || "", |
| | | specificationModel: p.specification || "", |
| | | uidNo: p.uidNo || "", |
| | | uidNo: p.uidNo || "", |
| | | unit: p.unit || "", |
| | | quantity: quantity, |
| | | taxRate: taxRate, |
| | |
| | | }; |
| | | |
| | | const batchNoOptions = ref([]); |
| | | const fetchBatchNoOptions = async () => { |
| | | const res = await getProductOrderBatchNoOptions(); |
| | | batchNoOptions.value = res.data; |
| | | }; |
| | | // 关闭弹框 |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | |
| | | productIndex.value = index; |
| | | // 编辑时根据产品大类名称反查 tree 节点 id,并加载规格型号列表 |
| | | try { |
| | | const options = productOptions.value && productOptions.value.length > 0 |
| | | ? productOptions.value |
| | | : await getProductOptions(); |
| | | const categoryId = findNodeIdByLabel(options, productForm.value.productCategory); |
| | | if (categoryId) { |
| | | const models = await modelList({ id: categoryId }); |
| | | modelOptions.value = models || []; |
| | | // 根据当前规格型号名称反查并设置 productModelId,便于下拉框显示已选值 |
| | | const currentModel = (modelOptions.value || []).find( |
| | | (m) => m.model === productForm.value.specificationModel |
| | | ); |
| | | if (!productOptions.value || productOptions.value.length === 0) { |
| | | await getProductOptions(); |
| | | } |
| | | |
| | | // 回显:根据“产品大类”反查产品节点 |
| | | const categoryKey = findNodeIdByLabel(productOptions.value, productForm.value.productCategory); |
| | | if (categoryKey) { |
| | | const categoryNode = findNodeObjByValue(stockInventoryAllTree, categoryKey); |
| | | const models = (categoryNode?.children || []) |
| | | .filter((n) => n.nodeType === "model") |
| | | .map((m) => ({ |
| | | id: m.value, |
| | | model: m.model ?? m.label ?? "", |
| | | unit: m.unit ?? "", |
| | | uidNo: m.uidNo ?? m.identifierCode ?? "", |
| | | })); |
| | | modelOptions.value = models; |
| | | |
| | | // 根据当前规格型号回显 |
| | | const targetSpec = String(productForm.value.specificationModel ?? "").trim(); |
| | | const currentModel = |
| | | (models || []).find((m) => String(m.model ?? "").trim() === targetSpec) || |
| | | (models || []).find((m) => String(m.model ?? "").trim().includes(targetSpec)) || |
| | | (models || []).find((m) => targetSpec.includes(String(m.model ?? "").trim())); |
| | | if (currentModel) { |
| | | productForm.value.customer = productForm.value.customer || row.customer || row.supplierName || ""; |
| | | productForm.value.productModelId = currentModel.id; |
| | | getProductModel(currentModel.id); |
| | | } |
| | | } |
| | | } catch (e) { |
| | | // 加载失败时保持可编辑,不中断弹窗 |
| | | console.error("加载产品规格型号失败", e); |
| | | } |
| | | // 最终兜底:如果中途被重置清空,至少回显行数据里的 UID |
| | | productForm.value.uidNo = row.uidNo ?? productForm.value.uidNo ?? ""; |
| | | // 最终兜底:同样保证单位不会因树数据缺失而被覆盖为空 |
| | | productForm.value.unit = row.unit ?? productForm.value.unit ?? ""; |
| | | } else { |
| | | getProductOptions() |
| | | } |
| | |
| | | <th>产品名称</th> |
| | | <th>规格型号</th> |
| | | <th>单位</th> |
| | | <th>UID码</th> |
| | | <th>单价</th> |
| | | <th>零售数量</th> |
| | | <th>零售金额</th> |
| | |
| | | <td>${product.productCategory || ''}</td> |
| | | <td>${product.specificationModel || ''}</td> |
| | | <td>${product.unit || ''}</td> |
| | | <td>${product.uidNo || ''}</td> |
| | | <td>${product.taxInclusiveUnitPrice || '0'}</td> |
| | | <td>${product.quantity || '0'}</td> |
| | | <td>${product.taxInclusiveTotalPrice || '0'}</td> |
| | |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | fetchBatchNoOptions(); |
| | | userListNoPage().then(res => { |
| | | userList.value = res.data; |
| | | }) |