| | |
| | | }) |
| | | } |
| | | |
| | | // 下载出库检验报告 |
| | | export function downloadOutReport(data) { |
| | | return request({ |
| | | url: '/quality/qualityInspect/downOutReport', |
| | | method: 'post', |
| | | data: data, |
| | | responseType: "blob", |
| | | }) |
| | | } |
| | |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="生产日期" |
| | | prop="productionDate" |
| | | > |
| | | <el-date-picker |
| | | v-model="formState.productionDate" |
| | | type="date" |
| | | placeholder="请选择生产日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item |
| | | label="供应商" |
| | | prop="customer" |
| | | :rules="[{ required: true, message: '请选择供应商', trigger: 'change' }]" |
| | |
| | | productModelName: "", |
| | | unit: "", |
| | | batchNo: "", |
| | | productionDate: "", |
| | | customer: "", |
| | | qualitity: 0, |
| | | warnNum: 0, |
| | |
| | | productModelName: "", |
| | | unit: "", |
| | | batchNo: "", |
| | | productionDate: "", |
| | | customer: "", |
| | | qualitity: 0, |
| | | warnNum: 0, |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">产品大类:</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> |
| | | <div class="search_form search_form--wrap"> |
| | | <div class="search-field"> |
| | | <span class="search_title">产品类型:</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> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true">新增库存</el-button> |
| | | <div class="search-field"> |
| | | <span class="search_title">产品名称:</span> |
| | | <el-input |
| | | v-model="searchForm.productName" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field"> |
| | | <span class="search_title">规格型号:</span> |
| | | <el-input |
| | | v-model="searchForm.model" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field"> |
| | | <span class="search_title">UID码:</span> |
| | | <el-input |
| | | v-model="searchForm.uidNo" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field"> |
| | | <span class="search_title">批次号:</span> |
| | | <el-input |
| | | v-model="searchForm.batchNo" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field search-field--actions"> |
| | | <el-button type="primary" @click="handleQuery">搜索</el-button> |
| | | <el-button type="primary" @click="isShowNewModal = true">新增库存</el-button> |
| | | <el-button type="info" plain icon="Upload" @click="isShowImportModal = true"> |
| | | 导入库存 |
| | | </el-button> |
| | |
| | | <div class="table_list"> |
| | | <el-table :data="tableData" border v-loading="tableLoading" @selection-change="handleSelectionChange" |
| | | :expand-row-keys="expandedRowKeys" :row-key="row => row.id" style="width: 100%" |
| | | :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)"> |
| | | :row-class-name="tableRowClassName" height="calc(100vh - 26.5em)"> |
| | | <el-table-column align="center" type="selection" width="55" /> |
| | | <el-table-column align="center" label="序号" type="index" width="60" /> |
| | | <el-table-column label="产品大类" prop="productName" 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 /> |
| | | <el-table-column label="库存预警数量" prop="warnNum" show-overflow-tooltip /> |
| | | <el-table-column label="库存预警数量" width="120" prop="warnNum" show-overflow-tooltip /> |
| | | <el-table-column label="生产日期" prop="productionDate" show-overflow-tooltip /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="操作" min-width="60" align="center"> |
| | | <el-table-column label="最近更新时间" width="120" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="操作" min-width="100" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">领用</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">冻结</el-button> |
| | |
| | | |
| | | <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 { searchForm } = toRefs(data) |
| | | |
| | | // 成品(2) / 其他产品(原材料1、半成品3),与产品类型字典一致;分页接口需支持 productType 或 productTypes |
| | | const productScope = ref('成品') |
| | | |
| | | const getProductScopeParams = () => { |
| | | return { productScope: productScope.value } |
| | | } |
| | | |
| | | const onProductScopeChange = () => { |
| | | page.current = 1 |
| | | getList() |
| | | } |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | |
| | | } |
| | | 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"> |
| | | .search_form--wrap { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 12px 16px; |
| | | } |
| | | |
| | | .search-field { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | flex: 0 1 auto; |
| | | min-width: 0; |
| | | gap: 8px; |
| | | |
| | | .search_title { |
| | | flex-shrink: 0; |
| | | white-space: nowrap; |
| | | text-align: right; |
| | | min-width: 4.5em; |
| | | } |
| | | |
| | | .search-input { |
| | | width: 200px; |
| | | } |
| | | |
| | | .qualified-product-scope { |
| | | flex-shrink: 0; |
| | | } |
| | | } |
| | | |
| | | .search-field--actions { |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | .qualified-product-scope { |
| | | vertical-align: middle; |
| | | } |
| | | |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <div class="search_form"> |
| | | <div> |
| | | <span class="search_title ml10">产品大类:</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> |
| | | <div class="search_form search_form--wrap"> |
| | | <div class="search-field"> |
| | | <span class="search_title">产品名称:</span> |
| | | <el-input |
| | | v-model="searchForm.productName" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="isShowNewModal = true">新增库存</el-button> |
| | | <div class="search-field"> |
| | | <span class="search_title">规格型号:</span> |
| | | <el-input |
| | | v-model="searchForm.model" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field"> |
| | | <span class="search_title">UID码:</span> |
| | | <el-input |
| | | v-model="searchForm.uidNo" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field"> |
| | | <span class="search_title">批次号:</span> |
| | | <el-input |
| | | v-model="searchForm.batchNo" |
| | | class="search-input" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </div> |
| | | <div class="search-field search-field--actions"> |
| | | <el-button type="primary" @click="handleQuery">搜索</el-button> |
| | | <el-button type="primary" @click="isShowNewModal = true">新增库存</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip /> |
| | | <el-table-column label="备注" prop="remark" show-overflow-tooltip /> |
| | | <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip /> |
| | | <el-table-column fixed="right" label="操作" min-width="60" align="center"> |
| | | <el-table-column fixed="right" label="操作" min-width="120" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" size="small" @click="showSubtractModal(scope.row)" :disabled="scope.row.unLockedQuantity === 0">领用</el-button> |
| | | <el-button link type="primary" size="small" v-if="scope.row.unLockedQuantity > 0" @click="showFrozenModal(scope.row)">冻结</el-button> |
| | |
| | | |
| | | <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 { ElMessageBox } from "element-plus"; |
| | | import { getStockUninventoryListPage } from "@/api/inventoryManagement/stockUninventory.js"; |
| | | const NewStockInventory = defineAsyncComponent(() => import("@/views/inventoryManagement/stockManagement/New.vue")); |
| | |
| | | const expandedRowKeys = ref([]) |
| | | |
| | | // 表格行类名 |
| | | const tableRowClassName = ({ row }) => { |
| | | // const stock = Number(row?.unLockedQuantity ?? 0); |
| | | // const warn = Number(row?.warnNum ?? 0); |
| | | // if (!Number.isFinite(stock) || !Number.isFinite(warn)) { |
| | | // return ''; |
| | | // } |
| | | // return stock < warn ? 'row-low-stock' : ''; |
| | | const tableRowClassName = () => { |
| | | return ''; |
| | | }; |
| | | |
| | | // 导出 |
| | |
| | | type: 'warning', |
| | | } |
| | | ).then(() => { |
| | | proxy.download("/stockUninventory/exportStockUninventory", {}, '不合格库存信息.xlsx') |
| | | proxy.download("/stockUninventory/exportStockUninventory", { ...searchForm.value }, '不合格库存信息.xlsx') |
| | | }).catch(() => { |
| | | proxy.$modal.msg("已取消") |
| | | }) |
| | |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .search_form--wrap { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | align-items: center; |
| | | gap: 12px 16px; |
| | | } |
| | | |
| | | .search-field { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | flex: 0 1 auto; |
| | | min-width: 0; |
| | | gap: 8px; |
| | | |
| | | .search_title { |
| | | flex-shrink: 0; |
| | | white-space: nowrap; |
| | | text-align: right; |
| | | min-width: 4.5em; |
| | | } |
| | | |
| | | .search-input { |
| | | width: 200px; |
| | | } |
| | | } |
| | | |
| | | .search-field--actions { |
| | | flex-wrap: wrap; |
| | | gap: 8px; |
| | | } |
| | | |
| | | :deep(.row-low-stock td) { |
| | | background-color: #fde2e2; |
| | | color: #c45656; |
| | |
| | | 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"> |
| | |
| | | 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: [ |
| | |
| | | const product = products[0]; |
| | | formState.value.productId = product.productId; |
| | | formState.value.productName = product.productName; |
| | | if (product.parentName === '一类产品') { |
| | | formState.value.manufacturingTeam = product.parentName.charAt(0) + '类车间'; |
| | | } |
| | | formState.value.manufacturingTeam = product.parentName.charAt(0) + '类车间'; |
| | | |
| | | formState.value.productModelName = product.model; |
| | | formState.value.productModelId = product.id; |
| | |
| | | </el-select> |
| | | </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> |
| | | </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-input v-model="form.uidNo" placeholder="请输入" disabled/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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-col :span="12"> |
| | | <el-form-item label="总数量:" prop="quantity"> |
| | | <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"> |
| | | <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" :disabled="quantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验用粉剂/液情况:" prop="inspectMaterialCondition"> |
| | | <el-radio-group v-model="form.inspectMaterialCondition"> |
| | | <el-radio label="检验用粉剂情况">检验用粉剂情况</el-radio> |
| | | <el-radio label="检验用液剂情况">检验用液剂情况</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="生产日期:" prop="productionDate"> |
| | | <el-date-picker |
| | | v-model="form.productionDate" |
| | | type="date" |
| | | placeholder="请选择日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="calculateValidityDate" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="有效期:" prop="validityDate"> |
| | | <el-date-picker |
| | | v-model="form.validityDate" |
| | | type="date" |
| | | placeholder="自动计算或手动选择" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </el-select> |
| | | </template> |
| | | <template #deviceStatus="{ row }"> |
| | | <el-tag v-if="row.deviceStatus" :type="getDeviceStatusType(row.deviceStatus)"> |
| | | {{ row.deviceStatus }} |
| | | </el-tag> |
| | | <span v-else style="color: #999">-</span> |
| | | <el-select |
| | | v-model="row.deviceStatus" |
| | | placeholder="请选择" |
| | | default-first-option |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option label="正常" value="正常" /> |
| | | <el-option label="停机" value="停机" /> |
| | | <el-option label="运行" value="运行" /> |
| | | <el-option label="维修" value="维修" /> |
| | | <el-option label="/" value="/" /> |
| | | </el-select> |
| | | </template> |
| | | <template #result="{ row }"> |
| | | <el-input v-model="row.result" 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: "", |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | inspectedQuantity: "", |
| | | quantity: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | | productionDate: "", |
| | | validityDate: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | |
| | | unit: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | inspectedQuantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | inspectedQuantity: [ |
| | | { required: true, message: "请输入检品数量", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (value !== '' && value !== null && value !== undefined) { |
| | | const qty = Number(form.value.quantity); |
| | | const inspectedQty = Number(value); |
| | | if (!isNaN(qty) && !isNaN(inspectedQty) && inspectedQty > qty) { |
| | | callback(new Error("检品数量不能大于总数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur" |
| | | } |
| | | ], |
| | | checkCompany: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请输入", trigger: "change" }], |
| | | }, |
| | | }); |
| | |
| | | prop: "standardValue", |
| | | width: 180 |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | width: 80 |
| | | }, |
| | | { |
| | | label: "检测器具", |
| | | prop: "instrument", |
| | | dataType: 'slot', |
| | | slot: 'instrument', |
| | | width: 220 |
| | | }, |
| | | { |
| | | label: "设备状态", |
| | | prop: "deviceStatus", |
| | | dataType: 'slot', |
| | | slot: 'deviceStatus', |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "检测结果", |
| | | prop: "result", |
| | | dataType: 'slot', |
| | | slot: 'result', |
| | | minWidth: 150 |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | width: 70 |
| | | }, |
| | | { |
| | | label: "检测器具", |
| | | prop: "instrument", |
| | | dataType: 'slot', |
| | | slot: 'instrument', |
| | | width: 220 |
| | | }, |
| | | { |
| | | label: "设备状态", |
| | | prop: "deviceStatus", |
| | | dataType: 'slot', |
| | | slot: 'deviceStatus', |
| | | width: 120 |
| | | }, |
| | | { |
| | | label: "检测结果", |
| | | prop: "result", |
| | | dataType: 'slot', |
| | | slot: 'result', |
| | | width: 150 |
| | | }, |
| | | { |
| | | label: "结果判断", |
| | | prop: "resultJudgment", |
| | |
| | | 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); |
| | |
| | | form.value.model = modelOptions.value.find(item => item.id == value)?.model || ''; |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | form.value.uidNo = modelOptions.value.find(item => item.id == value)?.uidNo || ''; |
| | | // 选择规格型号后,如果已有生产日期则重新计算有效期 |
| | | if (form.value.productionDate) { |
| | | calculateValidityDate(); |
| | | } |
| | | } |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | }) |
| | | } |
| | | |
| | | // 计算有效期(生产日期 + 规格型号中的有效期) |
| | | const calculateValidityDate = async () => { |
| | | if (!form.value.productionDate) { |
| | | form.value.validityDate = ''; |
| | | return; |
| | | } |
| | | // 获取规格型号的有效期 |
| | | const selectedModel = modelOptions.value.find(item => item.id == form.value.productModelId); |
| | | if (selectedModel && selectedModel.validityPeriod) { |
| | | const productionDate = new Date(form.value.productionDate); |
| | | const validityPeriod = parseFloat(selectedModel.validityPeriod); |
| | | const validityDate = new Date(productionDate); |
| | | validityDate.setFullYear(validityDate.getFullYear() + Math.floor(validityPeriod)); |
| | | validityDate.setMonth(validityDate.getMonth() + Math.round((validityPeriod % 1) * 12)); |
| | | form.value.validityDate = validityDate.toISOString().split('T')[0]; |
| | | } |
| | | }; |
| | | |
| | | // 获取设备台账列表 |
| | | const loadDeviceList = () => { |
| | | qualityInspectParamDeviceList().then(res => { |
| | |
| | | import {ElMessageBox} from "element-plus"; |
| | | import { |
| | | downloadQualityInspect, |
| | | downloadOutReport, |
| | | qualityInspectDel, |
| | | qualityInspectListPage, qualityInspectUpdate, |
| | | submitQualityInspect |
| | |
| | | return false; |
| | | } |
| | | }, |
| | | { |
| | | /*{ |
| | | name: "填写检验记录", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | |
| | | } |
| | | return false; |
| | | } |
| | | }, |
| | | },*/ |
| | | { |
| | | name: "附件", |
| | | type: "text", |
| | |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | downLoadFile(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "报告", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | downloadReport(row); |
| | | }, |
| | | }, |
| | | ], |
| | |
| | | type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
| | | }) |
| | | const downloadUrl = window.URL.createObjectURL(blob) |
| | | |
| | | |
| | | const link = document.createElement('a') |
| | | link.href = downloadUrl |
| | | link.download = '原材料检验报告.docx' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | |
| | | |
| | | document.body.removeChild(link) |
| | | window.URL.revokeObjectURL(downloadUrl) |
| | | }) |
| | | }; |
| | | |
| | | const downloadReport = (row) => { |
| | | downloadOutReport({ id: row.id }).then((blobData) => { |
| | | const blob = new Blob([blobData], { |
| | | type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', |
| | | }) |
| | | const downloadUrl = window.URL.createObjectURL(blob) |
| | | |
| | | const link = document.createElement('a') |
| | | link.href = downloadUrl |
| | | link.download = '出库检验报告.docx' |
| | | document.body.appendChild(link) |
| | | link.click() |
| | | |
| | | document.body.removeChild(link) |
| | | window.URL.revokeObjectURL(downloadUrl) |
| | | }) |
| | |
| | | </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: "", |
| | |
| | | <el-input |
| | | v-model="searchForm.productName" |
| | | style="width: 200px" |
| | | placeholder="请输入产品名称搜索" |
| | | @change="handleQuery" |
| | | clearable |
| | | :prefix-icon="Search" |
| | | /> |
| | |
| | | <el-button type="primary" @click="handleQuery" style="margin-left: 10px">搜索</el-button> |
| | | </div> |
| | | <div> |
| | | <el-button type="primary" @click="openForm('add')">新增</el-button> |
| | | <el-button @click="handleOut">导出</el-button> |
| | | <!-- <el-button type="primary" @click="openForm('add')">新增</el-button> --> |
| | | <!-- <el-button @click="handleOut">导出</el-button> --> |
| | | <el-button type="danger" plain @click="handleDelete">删除</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="数量:" prop="quantity"> |
| | | <el-form-item label="总数量:" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" clearable :precision="2" :disabled="processQuantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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" :disabled="processQuantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验用粉剂/液情况:" prop="inspectMaterialCondition"> |
| | | <el-radio-group v-model="form.inspectMaterialCondition"> |
| | | <el-radio label="粉剂">粉剂</el-radio> |
| | | <el-radio label="液体">液体</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="生产日期:" prop="productionDate"> |
| | | <el-date-picker |
| | | v-model="form.productionDate" |
| | | type="date" |
| | | placeholder="请选择日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="calculateValidityDate" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="有效期:" prop="validityDate"> |
| | | <el-date-picker |
| | | v-model="form.validityDate" |
| | | type="date" |
| | | placeholder="自动计算或手动选择" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | <el-input v-model="form.uidNo" placeholder="请输入" disabled/> |
| | | </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-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> |
| | |
| | | </el-select> |
| | | </template> |
| | | <template #deviceStatus="{ row }"> |
| | | <el-tag v-if="row.deviceStatus" :type="getDeviceStatusType(row.deviceStatus)"> |
| | | {{ row.deviceStatus }} |
| | | </el-tag> |
| | | <span v-else style="color: #999">-</span> |
| | | <el-select |
| | | v-model="row.deviceStatus" |
| | | placeholder="请选择" |
| | | default-first-option |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option label="正常" value="正常" /> |
| | | <el-option label="停机" value="停机" /> |
| | | <el-option label="运行" value="运行" /> |
| | | <el-option label="维修" value="维修" /> |
| | | <el-option label="/" value="/" /> |
| | | </el-select> |
| | | </template> |
| | | <template #result="{ row }"> |
| | | <el-input v-model="row.result" 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: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | | productionDate: "", |
| | | validityDate: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | |
| | | testStandardId: [{required: false, message: "请选择指标", trigger: "change"}], |
| | | unit: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | quantity: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | inspectedQuantity: [ |
| | | { required: true, message: "请输入检品数量", trigger: "blur" }, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (value !== '' && value !== null && value !== undefined) { |
| | | const qty = Number(form.value.quantity); |
| | | const inspectedQty = Number(value); |
| | | if (!isNaN(qty) && !isNaN(inspectedQty) && inspectedQty > qty) { |
| | | callback(new Error("检品数量不能大于总数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur" |
| | | } |
| | | ], |
| | | checkCompany: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{ required: true, message: "请输入", trigger: "change" }], |
| | | }, |
| | | }); |
| | |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | width: 80 |
| | | width: 70 |
| | | }, |
| | | { |
| | | label: "检测器具", |
| | |
| | | prop: "result", |
| | | dataType: 'slot', |
| | | slot: 'result', |
| | | minWidth: 150 |
| | | width: 150 |
| | | }, |
| | | { |
| | | label: "结果判断", |
| | |
| | | testStandardId: "", |
| | | unit: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | quantity: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | | productionDate: "", |
| | | validityDate: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | } |
| | |
| | | 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); |
| | |
| | | form.value.model = modelOptions.value.find(item => item.id == value)?.model || ''; |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | form.value.uidNo = modelOptions.value.find(item => item.id == value)?.uidNo || ''; |
| | | // 选择规格型号后,如果已有生产日期则重新计算有效期 |
| | | if (form.value.productionDate) { |
| | | calculateValidityDate(); |
| | | } |
| | | } |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | } |
| | | }; |
| | | |
| | | // 计算有效期(生产日期 + 规格型号中的有效期) |
| | | const calculateValidityDate = async () => { |
| | | if (!form.value.productionDate) { |
| | | form.value.validityDate = ''; |
| | | return; |
| | | } |
| | | // 获取规格型号的有效期 |
| | | const selectedModel = modelOptions.value.find(item => item.id == form.value.productModelId); |
| | | if (selectedModel && selectedModel.validityPeriod) { |
| | | const productionDate = new Date(form.value.productionDate); |
| | | const validityPeriod = parseFloat(selectedModel.validityPeriod); |
| | | const validityDate = new Date(productionDate); |
| | | validityDate.setFullYear(validityDate.getFullYear() + Math.floor(validityPeriod)); |
| | | validityDate.setMonth(validityDate.getMonth() + Math.round((validityPeriod % 1) * 12)); |
| | | form.value.validityDate = validityDate.toISOString().split('T')[0]; |
| | | } |
| | | }; |
| | | |
| | | // 关闭弹框 |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | return false; |
| | | } |
| | | }, |
| | | { |
| | | /*{ |
| | | name: "填写检验记录", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | |
| | | } |
| | | return false; |
| | | } |
| | | }, |
| | | },*/ |
| | | { |
| | | name: "附件", |
| | | type: "text", |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="数量:" prop="quantity"> |
| | | <el-form-item label="总数量:" prop="quantity"> |
| | | <el-input-number :step="0.01" :min="0" style="width: 100%" v-model="form.quantity" placeholder="请输入" |
| | | clearable :precision="2" :disabled="supplierQuantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <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" :disabled="supplierQuantityDisabled"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="检验用粉剂/液情况:" prop="inspectMaterialCondition"> |
| | | <el-radio-group v-model="form.inspectMaterialCondition"> |
| | | <el-radio label="粉剂">粉剂</el-radio> |
| | | <el-radio label="液体">液体</el-radio> |
| | | </el-radio-group> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="生产日期:" prop="productionDate"> |
| | | <el-date-picker |
| | | v-model="form.productionDate" |
| | | type="date" |
| | | placeholder="请选择日期" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | @change="calculateValidityDate" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="有效期:" prop="validityDate"> |
| | | <el-date-picker |
| | | v-model="form.validityDate" |
| | | type="date" |
| | | placeholder="自动计算或手动选择" |
| | | value-format="YYYY-MM-DD" |
| | | format="YYYY-MM-DD" |
| | | clearable |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </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%"> |
| | |
| | | </el-select> |
| | | </template> |
| | | <template #deviceStatus="{ row }"> |
| | | <el-tag v-if="row.deviceStatus" :type="getDeviceStatusType(row.deviceStatus)"> |
| | | {{ row.deviceStatus }} |
| | | </el-tag> |
| | | <span v-else style="color: #999">-</span> |
| | | <el-select |
| | | v-model="row.deviceStatus" |
| | | placeholder="请选择" |
| | | default-first-option |
| | | clearable |
| | | style="width: 100%" |
| | | > |
| | | <el-option label="正常" value="正常" /> |
| | | <el-option label="停机" value="停机" /> |
| | | <el-option label="运行" value="运行" /> |
| | | <el-option label="维修" value="维修" /> |
| | | <el-option label="/" value="/" /> |
| | | </el-select> |
| | | </template> |
| | | <template #result="{ row }"> |
| | | <el-input v-model="row.result" 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: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | | productionDate: "", |
| | | validityDate: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | }, |
| | |
| | | testStandardId: [{required: false, message: "请选择指标", trigger: "change"}], |
| | | unit: [{required: false, message: "请输入", trigger: "blur"}], |
| | | quantity: [{required: true, message: "请输入", trigger: "blur"}], |
| | | inspectedQuantity: [ |
| | | {required: true, message: "请输入检品数量", trigger: "blur"}, |
| | | { |
| | | validator: (rule, value, callback) => { |
| | | if (value !== '' && value !== null && value !== undefined) { |
| | | const qty = Number(form.value.quantity); |
| | | const inspectedQty = Number(value); |
| | | if (!isNaN(qty) && !isNaN(inspectedQty) && inspectedQty > qty) { |
| | | callback(new Error("检品数量不能大于总数量")); |
| | | } else { |
| | | callback(); |
| | | } |
| | | } else { |
| | | callback(); |
| | | } |
| | | }, |
| | | trigger: "blur" |
| | | } |
| | | ], |
| | | checkCompany: [{required: false, message: "请输入", trigger: "blur"}], |
| | | batchNo: [{ required: true, validator: validateBatchNo, trigger: "blur" }], |
| | | checkResult: [{required: true, message: "请选择检测结果", trigger: "change"}], |
| | | }, |
| | | }); |
| | |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | width: 80 |
| | | width: 70 |
| | | }, |
| | | { |
| | | label: "检测器具", |
| | |
| | | prop: "result", |
| | | dataType: 'slot', |
| | | slot: 'result', |
| | | minWidth: 150 |
| | | width: 150 |
| | | }, |
| | | { |
| | | label: "结果判断", |
| | |
| | | productModelId: "", |
| | | model: "", |
| | | uidNo: "", |
| | | batchNo: "", |
| | | testStandardId: "", |
| | | unit: "", |
| | | quantity: "", |
| | | inspectedQuantity: "", |
| | | inspectMaterialCondition: "", |
| | | productionDate: "", |
| | | validityDate: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | } |
| | |
| | | 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); |
| | |
| | | form.value.model = modelOptions.value.find(item => item.id == value)?.model || ''; |
| | | form.value.unit = modelOptions.value.find(item => item.id == value)?.unit || ''; |
| | | form.value.uidNo = modelOptions.value.find(item => item.id == value)?.uidNo || ''; |
| | | // 选择规格型号后,如果已有生产日期则重新计算有效期 |
| | | if (form.value.productionDate) { |
| | | calculateValidityDate(); |
| | | } |
| | | } |
| | | |
| | | const findNodeById = (nodes, productId) => { |
| | |
| | | } |
| | | }; |
| | | |
| | | // 计算有效期(生产日期 + 规格型号中的有效期) |
| | | const calculateValidityDate = async () => { |
| | | if (!form.value.productionDate) { |
| | | form.value.validityDate = ''; |
| | | return; |
| | | } |
| | | // 获取规格型号的有效期 |
| | | const selectedModel = modelOptions.value.find(item => item.id == form.value.productModelId); |
| | | if (selectedModel && selectedModel.validityPeriod) { |
| | | const productionDate = new Date(form.value.productionDate); |
| | | const validityPeriod = parseFloat(selectedModel.validityPeriod); |
| | | const validityDate = new Date(productionDate); |
| | | validityDate.setFullYear(validityDate.getFullYear() + Math.floor(validityPeriod)); |
| | | validityDate.setMonth(validityDate.getMonth() + Math.round((validityPeriod % 1) * 12)); |
| | | form.value.validityDate = validityDate.toISOString().split('T')[0]; |
| | | } |
| | | }; |
| | | |
| | | // 关闭弹框 |
| | | const closeDia = () => { |
| | | proxy.resetForm("formRef"); |
| | |
| | | prop: "uidNo", |
| | | }, |
| | | { |
| | | label: "批号", |
| | | prop: "batchNo", |
| | | width: 140, |
| | | }, |
| | | { |
| | | label: "单位", |
| | | prop: "unit", |
| | | }, |
| | |
| | | return false; |
| | | } |
| | | }, |
| | | { |
| | | /*{ |
| | | name: "填写检验记录", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | |
| | | } |
| | | return false; |
| | | } |
| | | }, |
| | | },*/ |
| | | { |
| | | name: "附件", |
| | | type: "text", |
| | |
| | | { 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="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-table-column prop="salesperson" label="业务员" width="100" /> |
| | | <el-table-column prop="quotationDate" label="报价日期" width="120" /> |
| | | <el-table-column prop="validDate" label="有效期至" width="120" /> |
| | | <el-table-column prop="status" label="审批状态" width="120" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)" disable-transitions> |
| | | {{ row.status || '--' }} |
| | | </el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="totalAmount" label="报价金额" width="120"> |
| | | <template #default="scope"> |
| | | ¥{{ scope.row.totalAmount.toFixed(2) }} |
| | |
| | | <el-table-column label="操作" width="200" fixed="right" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="handleView(scope.row)">查看</el-button> |
| | | <el-button link type="primary" @click="handleEdit(scope.row)" :disabled="!['待审批','拒绝'].includes(scope.row.status)">编辑</el-button> |
| | | <el-button link type="primary" @click="handleEdit(scope.row)">编辑</el-button> |
| | | <el-button link type="danger" @click="handleDelete(scope.row)">删除</el-button> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="24"> |
| | | <!-- <el-row :gutter="24"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="付款方式" prop="paymentMethod"> |
| | | <el-input v-model="form.paymentMethod" placeholder="请输入付款方式" clearable /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </div> |
| | | </el-card> |
| | | |
| | | <!-- 审批人信息 --> |
| | | <el-card class="form-card" shadow="hover"> |
| | | <template #header> |
| | | <div class="card-header-wrapper"> |
| | | <el-icon class="card-icon"><UserFilled /></el-icon> |
| | | <span class="card-title">审批人选择</span> |
| | | <el-button type="primary" size="small" @click="addApproverNode" class="header-btn"> |
| | | <el-icon><Plus /></el-icon> |
| | | 新增节点 |
| | | </el-button> |
| | | </div> |
| | | </template> |
| | | <div class="form-content"> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item> |
| | | <div class="approver-nodes-container"> |
| | | <div |
| | | v-for="(node, index) in approverNodes" |
| | | :key="node.id" |
| | | class="approver-node-item" |
| | | > |
| | | <div class="approver-node-label"> |
| | | <span class="node-step">{{ index + 1 }}</span> |
| | | <span class="node-text">审批人</span> |
| | | <el-icon class="arrow-icon"><ArrowRight /></el-icon> |
| | | </div> |
| | | <el-select |
| | | v-model="node.userId" |
| | | placeholder="选择人员" |
| | | class="approver-select" |
| | | clearable |
| | | > |
| | | <el-option |
| | | v-for="user in userList" |
| | | :key="user.userId" |
| | | :label="user.nickName" |
| | | :value="user.userId" |
| | | /> |
| | | </el-select> |
| | | <el-button |
| | | type="danger" |
| | | size="small" |
| | | :icon="Delete" |
| | | @click="removeApproverNode(index)" |
| | | v-if="approverNodes.length > 1" |
| | | class="remove-btn" |
| | | >删除</el-button> |
| | | </div> |
| | | </div> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-row> --> |
| | | </div> |
| | | </el-card> |
| | | |
| | |
| | | <script setup> |
| | | import { ref, reactive, computed, onMounted, markRaw, shallowRef } from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { Search, Document, UserFilled, Box, EditPen, Plus, ArrowRight, Delete } from '@element-plus/icons-vue' |
| | | import { Search, Document, Box, EditPen, Plus } from '@element-plus/icons-vue' |
| | | import Pagination from '@/components/PIMTable/Pagination.vue' |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue' |
| | | import {getQuotationList,addQuotation,updateQuotation,deleteQuotation} from '@/api/salesManagement/salesQuotation.js' |
| | |
| | | const userList = ref([]); |
| | | const customerOption = ref([]); |
| | | |
| | | // 审批人节点相关 |
| | | const approverNodes = ref([ |
| | | { id: 1, userId: null } |
| | | ]) |
| | | let nextApproverId = 2 |
| | | |
| | | const isEdit = ref(false) |
| | | const editId = ref(null) |
| | | const currentQuotation = ref({}) |
| | | const formRef = ref() |
| | | |
| | | // 添加审批人节点 |
| | | function addApproverNode() { |
| | | approverNodes.value.push({ id: nextApproverId++, userId: null }) |
| | | } |
| | | |
| | | // 删除审批人节点 |
| | | function removeApproverNode(index) { |
| | | approverNodes.value.splice(index, 1) |
| | | } |
| | | |
| | | // 计算属性 |
| | | const filteredList = computed(() => { |
| | |
| | | }) |
| | | |
| | | // 方法 |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | '待审批': 'info', |
| | | '审核中': 'primary', |
| | | '通过': 'success', |
| | | '拒绝': 'danger' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | const resetSearch = () => { |
| | | searchForm.quotationNo = '' |
| | | searchForm.customer = '' |
| | |
| | | dialogTitle.value = '新增报价' |
| | | isEdit.value = false |
| | | resetForm() |
| | | // 重置审批人节点 |
| | | approverNodes.value = [{ id: 1, userId: null }] |
| | | nextApproverId = 2 |
| | | dialogVisible.value = true |
| | | let userLists = await userListNoPage(); |
| | | // 只复制需要的字段,避免将组件引用放入响应式对象 |
| | |
| | | form.discountAmount = row.discountAmount || 0 |
| | | form.totalAmount = row.totalAmount || 0 |
| | | |
| | | // 反显审批人 |
| | | if (row.approveUserIds) { |
| | | const userIds = row.approveUserIds.split(',') |
| | | approverNodes.value = userIds.map((userId, idx) => ({ |
| | | id: idx + 1, |
| | | userId: parseInt(userId.trim()) |
| | | })) |
| | | nextApproverId = userIds.length + 1 |
| | | } else { |
| | | approverNodes.value = [{ id: 1, userId: null }] |
| | | nextApproverId = 2 |
| | | } |
| | | |
| | | // 加载用户列表 |
| | | let userLists = await userListNoPage(); |
| | | userList.value = (userLists.data || []).map(item => ({ |
| | |
| | | return |
| | | } |
| | | |
| | | // 审批人必填校验 |
| | | const hasEmptyApprover = approverNodes.value.some(node => !node.userId) |
| | | if (hasEmptyApprover) { |
| | | ElMessage.error('请为所有审批节点选择审批人!') |
| | | return |
| | | } |
| | | |
| | | // 收集所有节点的审批人id |
| | | form.approveUserIds = approverNodes.value.map(node => node.userId).join(',') |
| | | |
| | | // 计算所有产品的单价总和 |
| | | form.totalAmount = form.products.reduce((sum, product) => { |
| | | const price = Number(product.unitPrice) || 0 |
| | |
| | | validDate: item.validDate || '', |
| | | paymentMethod: item.paymentMethod || '', |
| | | status: item.status || '草稿', |
| | | // 审批人(用于编辑时反显) |
| | | approveUserIds: item.approveUserIds || '', |
| | | remark: item.remark || '', |
| | | products: item.products ? item.products.map(product => ({ |
| | | productId: product.productId || '', |
| | |
| | | } |
| | | } |
| | | |
| | | .approver-nodes-container { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 24px; |
| | | padding: 12px 0; |
| | | } |
| | | |
| | | .approver-node-item { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | gap: 12px; |
| | | padding: 16px; |
| | | background: #f8f9fa; |
| | | border-radius: 8px; |
| | | border: 1px solid #e4e7ed; |
| | | transition: all 0.3s ease; |
| | | min-width: 180px; |
| | | |
| | | &:hover { |
| | | border-color: #409eff; |
| | | background: #f0f7ff; |
| | | box-shadow: 0 2px 8px rgba(64, 158, 255, 0.1); |
| | | } |
| | | } |
| | | |
| | | .approver-node-label { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 8px; |
| | | font-size: 14px; |
| | | color: #606266; |
| | | |
| | | .node-step { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | width: 24px; |
| | | height: 24px; |
| | | background: #409eff; |
| | | color: #fff; |
| | | border-radius: 50%; |
| | | font-size: 12px; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .node-text { |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .arrow-icon { |
| | | color: #909399; |
| | | font-size: 14px; |
| | | } |
| | | } |
| | | |
| | | .approver-select { |
| | | width: 100%; |
| | | min-width: 150px; |
| | | } |
| | | |
| | | .remove-btn { |
| | | margin-top: 4px; |
| | | } |
| | | |
| | | .product-table { |
| | | :deep(.el-table__header) { |
| | | background-color: #f5f7fa; |
| | |
| | | text-align: right; |
| | | } |
| | | |
| | | // 响应式优化 |
| | | @media (max-width: 1200px) { |
| | | .approver-nodes-container { |
| | | gap: 16px; |
| | | } |
| | | |
| | | .approver-node-item { |
| | | min-width: 160px; |
| | | } |
| | | } |
| | | </style> |