| | |
| | | <div> |
| | | <el-dialog |
| | | v-model="dialogFormVisible" |
| | | :title="operationType === 'add' ? '新增原材料检验' : '编辑原材料检验'" |
| | | :title="operationType === 'add' ? '新增不合格处理' : '处理不合格'" |
| | | width="70%" |
| | | @close="closeDia" |
| | | > |
| | | <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="状态:" prop="inspectState"> |
| | | <el-select v-model="form.inspectState"> |
| | | <el-option label="待处理" :value="0" /> |
| | | <el-option label="已处理" :value="1" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="类别:" prop="inspectType"> |
| | | <el-select v-model="form.inspectType" disabled> |
| | |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="处理结果:" prop="dealResult"> |
| | | <el-input v-model="form.dealResult" placeholder="请输入" clearable/> |
| | | <el-select v-model="form.dealResult" placeholder="请选择" clearable> |
| | | <el-option :label="item.label" :value="item.value" v-for="item in filteredRejectionHandling" :key="item.value" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="处理人:" prop="dealName"> |
| | | <el-input v-model="form.dealName" placeholder="请输入" clearable/> |
| | | <el-select v-model="form.dealName" placeholder="请选择" clearable style="width: 100%"> |
| | | <el-option v-for="item in userList" :key="item.nickName" :label="item.nickName" :value="item.nickName"/> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="工时损失:" prop="lossWorking"> |
| | | <el-input-number |
| | | v-model="form.lossWorking" |
| | | :min="0" |
| | | :step="0.01" |
| | | :precision="2" |
| | | style="width: 100%" |
| | | placeholder="请输入" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="材料费损失:" prop="lossMaterial"> |
| | | <el-input-number |
| | | v-model="form.lossMaterial" |
| | | :min="0" |
| | | :step="0.01" |
| | | :precision="2" |
| | | style="width: 100%" |
| | | placeholder="请输入" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="原因分析:" prop="reasonAnalysis"> |
| | | <el-input |
| | | v-model="form.reasonAnalysis" |
| | | type="textarea" |
| | | :rows="4" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="预防与纠正措施:" prop="preventiveCorrective"> |
| | | <el-input |
| | | v-model="form.preventiveCorrective" |
| | | type="textarea" |
| | | :rows="4" |
| | | placeholder="请输入" |
| | | clearable |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="不良品照片:" prop="defectivePhotos"> |
| | | <el-upload |
| | | v-model:file-list="defectivePhotoFileList" |
| | | :action="upload.url" |
| | | multiple |
| | | ref="defectivePhotoUploadRef" |
| | | auto-upload |
| | | accept="image/*" |
| | | :headers="upload.headers" |
| | | :before-upload="handleBeforeUpload" |
| | | :on-error="handleUploadError" |
| | | :on-success="handleDefectivePhotoUploadSuccess" |
| | | :on-remove="handleDefectivePhotoRemove" |
| | | > |
| | | <el-button type="primary" v-if="operationType !== 'view'">上传</el-button> |
| | | <template #tip v-if="operationType !== 'view'"> |
| | | <div class="el-upload__tip"> |
| | | 文件格式支持 jpg,jpeg,png,gif,bmp |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {ref} from "vue"; |
| | | import { ref, reactive, toRefs, computed, watch, getCurrentInstance } from "vue"; |
| | | import {productTreeList} from "@/api/basicData/product.js"; |
| | | import { |
| | | getQualityUnqualifiedInfo, |
| | | qualityUnqualifiedAdd, |
| | | qualityUnqualifiedUpdate |
| | | qualityUnqualifiedDeal |
| | | } from "@/api/qualityManagement/nonconformingManagement.js"; |
| | | import {userListNoPage} from "@/api/system/user.js"; |
| | | import { getToken } from "@/utils/auth"; |
| | | const { proxy } = getCurrentInstance() |
| | | const emit = defineEmits(['close']) |
| | | |
| | | const { rejection_handling } = proxy.useDict("rejection_handling") |
| | | const dialogFormVisible = ref(false); |
| | | const operationType = ref('') |
| | | const defectivePhotoFileList = ref([]); |
| | | const defectivePhotoUploadRef = ref(null); |
| | | const upload = reactive({ |
| | | url: import.meta.env.VITE_APP_BASE_API + "/file/upload", |
| | | headers: { Authorization: "Bearer " + getToken() }, |
| | | }); |
| | | const data = reactive({ |
| | | form: { |
| | | checkTime: "", |
| | |
| | | quantity: "", |
| | | checkCompany: "", |
| | | checkResult: "", |
| | | inspectState: '', |
| | | inspectType: '', |
| | | defectivePhenomena: '', |
| | | defectivePhotos: '', |
| | | tempFileIds: [], |
| | | commonFileList: [], |
| | | dealResult: '', |
| | | dealName: '', |
| | | dealTime: '', |
| | | method: undefined, |
| | | reasonAnalysis: '', |
| | | preventiveCorrective: '', |
| | | lossWorking: 0, |
| | | lossMaterial: 0, |
| | | }, |
| | | rules: { |
| | | checkTime: [{ required: false, message: "请输入", trigger: "blur" },], |
| | |
| | | checkResult: [{ required: false, message: "请输入", trigger: "blur" }], |
| | | defectivePhenomena: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | dealResult: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | dealName: [{ required: true, message: "请输入", trigger: "blur" }], |
| | | dealName: [{ required: true, message: "请选择处理人", trigger: "change" }], |
| | | dealTime: [{ required: true, message: "请输入", trigger: "change" }], |
| | | }, |
| | | }); |
| | | const { form, rules } = toRefs(data); |
| | | const productOptions = ref([]); |
| | | const userList = ref([]); // 处理人下拉列表 |
| | | |
| | | const filteredRejectionHandling = computed(() => { |
| | | const data = rejection_handling.value; |
| | | if (form.value.method) { |
| | | return data.filter(item => item && item.label && item.label !== '返工' && item.label !== '返修') |
| | | } |
| | | return data |
| | | }) |
| | | |
| | | |
| | | // 打开弹框 |
| | | const openDialog = (type, row) => { |
| | | const openDialog = async (type, row) => { |
| | | operationType.value = type; |
| | | // 处理人下拉列表 |
| | | try { |
| | | const userRes = await userListNoPage(); |
| | | userList.value = userRes.data || []; |
| | | } catch (e) { |
| | | console.error("加载用户列表失败", e); |
| | | userList.value = []; |
| | | } |
| | | dialogFormVisible.value = true; |
| | | form.value = {} |
| | | defectivePhotoFileList.value = []; |
| | | form.value = { |
| | | reasonAnalysis: '', |
| | | preventiveCorrective: '', |
| | | lossWorking: 0, |
| | | lossMaterial: 0, |
| | | defectivePhotos: '', |
| | | tempFileIds: [], |
| | | commonFileList: [], |
| | | }; |
| | | getProductOptions(); |
| | | if (operationType.value === 'edit') { |
| | | getQualityUnqualifiedInfo(row.id).then(res => { |
| | | form.value = {...res.data} |
| | | const { inspectState, ...rest } = (res.data || {}) |
| | | // 有数据就显示默认值,没有就不显示 |
| | | form.value = { |
| | | reasonAnalysis: '', |
| | | preventiveCorrective: '', |
| | | lossWorking: 0, |
| | | lossMaterial: 0, |
| | | defectivePhotos: '', |
| | | tempFileIds: [], |
| | | commonFileList: [], |
| | | ...rest |
| | | } |
| | | }) |
| | | } |
| | | } |
| | |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "add") { |
| | | qualityUnqualifiedAdd(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | closeDia(); |
| | | }) |
| | | } else { |
| | | qualityUnqualifiedUpdate(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | closeDia(); |
| | | }) |
| | | } |
| | | // 状态字段不在表单填写,也不传给后端;处理统一走 /deal 接口 |
| | | const { inspectState, ...payload } = (form.value || {}) |
| | | qualityUnqualifiedDeal(payload).then(() => { |
| | | proxy.$modal.msgSuccess("提交成功"); |
| | | closeDia(); |
| | | }) |
| | | } |
| | | }) |
| | | } |
| | | // 上传前校检(与新增页一致) |
| | | function handleBeforeUpload() { |
| | | proxy.$modal.loading("正在上传文件,请稍候..."); |
| | | return true; |
| | | } |
| | | function handleUploadError() { |
| | | proxy.$modal.msgError("上传文件失败"); |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | // 不良品照片上传成功:保存 tempId 与 tempPath,并回写到表单 |
| | | function handleDefectivePhotoUploadSuccess(res, file) { |
| | | proxy.$modal.closeLoading(); |
| | | if (res?.code === 200) { |
| | | const tempId = res?.data?.tempId; |
| | | const tempPath = res?.data?.tempPath || res?.data?.url || ""; |
| | | const originalName = res?.data?.originalName || file?.name || "图片"; |
| | | |
| | | if (!form.value.tempFileIds) form.value.tempFileIds = []; |
| | | if (tempId) form.value.tempFileIds.push(tempId); |
| | | |
| | | file.id = tempId || file.id; |
| | | file.name = originalName; |
| | | file.url = tempPath ? (import.meta.env.VITE_APP_BASE_API + tempPath) : file.url; |
| | | |
| | | syncDefectivePhotosFromFileList(); |
| | | proxy.$modal.msgSuccess("上传成功"); |
| | | } else { |
| | | proxy.$modal.msgError(res?.msg || "上传失败"); |
| | | defectivePhotoUploadRef.value?.handleRemove(file); |
| | | } |
| | | } |
| | | function handleDefectivePhotoRemove(file) { |
| | | const tempId = file?.id || file?.response?.data?.tempId; |
| | | if (tempId && Array.isArray(form.value.tempFileIds)) { |
| | | form.value.tempFileIds = form.value.tempFileIds.filter(id => id !== tempId); |
| | | } |
| | | if (Array.isArray(form.value.commonFileList)) { |
| | | form.value.commonFileList = form.value.commonFileList.filter(item => { |
| | | return item?.id !== tempId && item?.url !== file?.url && item?.name !== file?.name; |
| | | }); |
| | | } |
| | | syncDefectivePhotosFromFileList(); |
| | | } |
| | | function syncDefectivePhotosFromFileList() { |
| | | const base = import.meta.env.VITE_APP_BASE_API; |
| | | const paths = (defectivePhotoFileList.value || []) |
| | | .map(f => f?.url || f?.response?.data?.tempPath || f?.response?.data?.url) |
| | | .filter(Boolean) |
| | | .map(url => (typeof url === "string" ? url.replace(base, "") : "")) |
| | | .filter(Boolean); |
| | | form.value.defectivePhotos = paths.join(","); |
| | | } |
| | | function buildDefectivePhotoFileList() { |
| | | const commonFiles = Array.isArray(form.value?.commonFileList) ? form.value.commonFileList : []; |
| | | if (commonFiles.length > 0) { |
| | | defectivePhotoFileList.value = commonFiles |
| | | .map((item, idx) => ({ |
| | | name: item?.name || `图片${idx + 1}`, |
| | | url: item?.url || "", |
| | | id: item?.id, |
| | | })) |
| | | .filter(item => item.url); |
| | | return; |
| | | } |
| | | |
| | | const photos = form.value?.defectivePhotos; |
| | | if (!photos) { |
| | | defectivePhotoFileList.value = []; |
| | | return; |
| | | } |
| | | const base = import.meta.env.VITE_APP_BASE_API; |
| | | defectivePhotoFileList.value = String(photos) |
| | | .split(",") |
| | | .map((p, idx) => { |
| | | const path = p?.trim(); |
| | | if (!path) return null; |
| | | return { |
| | | name: `图片${idx + 1}`, |
| | | url: path.startsWith("http") ? path : base + path, |
| | | id: undefined, |
| | | }; |
| | | }) |
| | | .filter(Boolean); |
| | | } |
| | | |
| | | watch( |
| | | () => [form.value?.defectivePhotos, form.value?.commonFileList], |
| | | () => { |
| | | buildDefectivePhotoFileList(); |
| | | }, |
| | | { immediate: true, deep: true } |
| | | ); |
| | | // 关闭弹框 |
| | | const closeDia = () => { |
| | | defectivePhotoFileList.value = [] |
| | | proxy.resetForm("formRef"); |
| | | dialogFormVisible.value = false; |
| | | emit('close') |