|  |  | 
 |  |  |             </el-col> | 
 |  |  |             <el-col :span="12"> | 
 |  |  |               <el-form-item label="交货期" prop="deliveryPeriod"> | 
 |  |  |                 <el-input v-model="form.deliveryPeriod" placeholder="请输入交货期" /> | 
 |  |  |                 <el-date-picker | 
 |  |  |                   v-model="form.deliveryPeriod" | 
 |  |  |                   type="date" | 
 |  |  |                   placeholder="选择交货期" | 
 |  |  |                   style="width: 100%" | 
 |  |  |                   format="YYYY-MM-DD" | 
 |  |  |                   value-format="YYYY-MM-DD" | 
 |  |  |                 /> | 
 |  |  |               </el-form-item> | 
 |  |  |             </el-col> | 
 |  |  |           </el-row> | 
 |  |  | 
 |  |  |           <el-table :data="form.products" border style="width: 100%"> | 
 |  |  |             <el-table-column prop="product" label="产品名称" width="200"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-input v-model="scope.row.product" placeholder="请输入产品名称" /> | 
 |  |  |                                 <el-tree-select | 
 |  |  |                                     v-model="scope.row.productId" | 
 |  |  |                                     placeholder="请选择" | 
 |  |  |                                     clearable | 
 |  |  |                                     check-strictly | 
 |  |  |                                     @change="getModels($event, scope.row)" | 
 |  |  |                                     :data="productOptions" | 
 |  |  |                                     :render-after-expand="false" | 
 |  |  |                                     style="width: 100%" | 
 |  |  |                                 /> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="specification" label="规格型号" width="150"> | 
 |  |  |               <template #default="scope"> | 
 |  |  |                 <el-input v-model="scope.row.specification" placeholder="规格型号" /> | 
 |  |  |                                 <el-select | 
 |  |  |                                     v-model="scope.row.specificationId" | 
 |  |  |                                     placeholder="请选择" | 
 |  |  |                                     clearable | 
 |  |  |                                     @change="getProductModel($event, scope.row)" | 
 |  |  |                                 > | 
 |  |  |                                     <el-option | 
 |  |  |                                         v-for="item in modelOptions" | 
 |  |  |                                         :key="item.id" | 
 |  |  |                                         :label="item.model" | 
 |  |  |                                         :value="item.id" | 
 |  |  |                                     /> | 
 |  |  |                                 </el-select> | 
 |  |  |               </template> | 
 |  |  |             </el-table-column> | 
 |  |  |             <el-table-column prop="quantity" label="数量"> | 
 |  |  | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | <script setup> | 
 |  |  | import { ref, reactive, computed,onMounted  } from 'vue' | 
 |  |  | import { ref, reactive, computed, onMounted, markRaw, shallowRef } from 'vue' | 
 |  |  | import { ElMessage, ElMessageBox } from 'element-plus' | 
 |  |  | import { Search } from '@element-plus/icons-vue' | 
 |  |  | // import Pagination from '@/components/PIMTable/Pagination.vue' | 
 |  |  | import Pagination from '@/components/PIMTable/Pagination.vue' | 
 |  |  | import {getQuotationList,addQuotation,updateQuotation,deleteQuotation} from '@/api/salesManagement/salesQuotation.js' | 
 |  |  | import {userListNoPage} from "@/api/system/user.js"; | 
 |  |  | import {customerList} from "@/api/salesManagement/salesLedger.js"; | 
 |  |  | import {modelList, productTreeList} from "@/api/basicData/product.js"; | 
 |  |  |  | 
 |  |  | // 响应式数据 | 
 |  |  | const loading = ref(false) | 
 |  |  | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const quotationList = ref([]) | 
 |  |  |  | 
 |  |  | const productOptions = ref([]); | 
 |  |  | const modelOptions = ref([]); | 
 |  |  | const pagination = reactive({ | 
 |  |  |   total: 3, | 
 |  |  |   currentPage: 1, | 
 |  |  |   pageSize: 10 | 
 |  |  |   pageSize: 100 | 
 |  |  | }) | 
 |  |  |  | 
 |  |  | const dialogVisible = ref(false) | 
 |  |  | 
 |  |  |   quotationDate: [{ required: true, message: '请选择报价日期', trigger: 'change' }], | 
 |  |  |   validDate: [{ required: true, message: '请选择有效期', trigger: 'change' }], | 
 |  |  |   paymentMethod: [{ required: true, message: '请选择付款方式', trigger: 'change' }], | 
 |  |  |   deliveryPeriod: [{ required: true, message: '请输入交货期', trigger: 'blur' }] | 
 |  |  |   deliveryPeriod: [{ required: true, message: '请选择交货期', trigger: 'change' }] | 
 |  |  | } | 
 |  |  | const userList = ref([]); | 
 |  |  | const customerOption = ref([]); | 
 |  |  | 
 |  |  |   resetForm() | 
 |  |  |   dialogVisible.value = true | 
 |  |  |     let userLists = await userListNoPage(); | 
 |  |  |     userList.value = userLists.data; | 
 |  |  |     // 只复制需要的字段,避免将组件引用放入响应式对象 | 
 |  |  |     userList.value = (userLists.data || []).map(item => ({ | 
 |  |  |     userId: item.userId, | 
 |  |  |     nickName: item.nickName || '', | 
 |  |  |     userName: item.userName || '' | 
 |  |  |   })); | 
 |  |  |     getProductOptions(); | 
 |  |  |     customerList().then((res) => { | 
 |  |  |         customerOption.value = res; | 
 |  |  |         // 只复制需要的字段,避免将组件引用放入响应式对象 | 
 |  |  |         customerOption.value = (Array.isArray(res) ? res : []).map(item => ({ | 
 |  |  |       id: item.id, | 
 |  |  |       customerName: item.customerName || '', | 
 |  |  |       taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || '' | 
 |  |  |     })) | 
 |  |  |     }); | 
 |  |  | } | 
 |  |  |  | 
 |  |  | const getProductOptions = () => { | 
 |  |  |     productTreeList().then((res) => { | 
 |  |  |         productOptions.value = convertIdToValue(res); | 
 |  |  |     }); | 
 |  |  | }; | 
 |  |  | 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; | 
 |  |  |     }); | 
 |  |  | } | 
 |  |  | const getModels = (value, row) => { | 
 |  |  |     if (!row) return; | 
 |  |  |     // 如果清空选择,则清空相关字段 | 
 |  |  |     if (!value) { | 
 |  |  |         row.productId = ''; | 
 |  |  |         row.product = ''; | 
 |  |  |         modelOptions.value = []; | 
 |  |  |         row.specificationId = ''; | 
 |  |  |         row.specification = ''; | 
 |  |  |         row.unit = ''; | 
 |  |  |         return; | 
 |  |  |     } | 
 |  |  |     // 更新 productId(v-model 已经自动更新,这里确保一致性) | 
 |  |  |     row.productId = value; | 
 |  |  |     // 找到对应的 label 并赋值给 row.product | 
 |  |  |     const label = findNodeById(productOptions.value, value); | 
 |  |  |     if (label) { | 
 |  |  |         row.product = label; | 
 |  |  |     } | 
 |  |  |     // 获取规格型号列表 | 
 |  |  |     modelList({ id: value }).then((res) => { | 
 |  |  |         modelOptions.value = res || []; | 
 |  |  |     }); | 
 |  |  | }; | 
 |  |  | const getProductModel = (value, row) => { | 
 |  |  |     if (!row) return; | 
 |  |  |     // 如果清空选择,则清空相关字段 | 
 |  |  |     if (!value) { | 
 |  |  |         row.specificationId = ''; | 
 |  |  |         row.specification = ''; | 
 |  |  |         row.unit = ''; | 
 |  |  |         return; | 
 |  |  |     } | 
 |  |  |     // 更新 specificationId(v-model 已经自动更新,这里确保一致性) | 
 |  |  |     row.specificationId = value; | 
 |  |  |     const index = modelOptions.value.findIndex((item) => item.id === value); | 
 |  |  |     if (index !== -1) { | 
 |  |  |         row.specification = modelOptions.value[index].model; | 
 |  |  |         row.unit = modelOptions.value[index].unit; | 
 |  |  |     } else { | 
 |  |  |         row.specification = ''; | 
 |  |  |         row.unit = ''; | 
 |  |  |     } | 
 |  |  | }; | 
 |  |  | const findNodeById = (nodes, productId) => { | 
 |  |  |     for (let i = 0; i < nodes.length; i++) { | 
 |  |  |         if (nodes[i].value === productId) { | 
 |  |  |             return nodes[i].label; // 找到节点,返回 label | 
 |  |  |         } | 
 |  |  |         if (nodes[i].children && nodes[i].children.length > 0) { | 
 |  |  |             const foundLabel = findNodeById(nodes[i].children, productId); | 
 |  |  |             if (foundLabel) { | 
 |  |  |                 return foundLabel; // 在子节点中找到,返回 label | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |     return null; // 没有找到节点,返回null | 
 |  |  | }; | 
 |  |  | const handleView = (row) => { | 
 |  |  |   currentQuotation.value = row | 
 |  |  |   // 只复制需要的字段,避免将组件引用放入响应式对象 | 
 |  |  |   currentQuotation.value = { | 
 |  |  |     quotationNo: row.quotationNo || '', | 
 |  |  |     customer: row.customer || '', | 
 |  |  |     salesperson: row.salesperson || '', | 
 |  |  |     quotationDate: row.quotationDate || '', | 
 |  |  |     validDate: row.validDate || '', | 
 |  |  |     paymentMethod: row.paymentMethod || '', | 
 |  |  |     deliveryPeriod: row.deliveryPeriod || '', | 
 |  |  |     status: row.status || '', | 
 |  |  |     remark: row.remark || '', | 
 |  |  |     products: row.products ? row.products.map(product => ({ | 
 |  |  |       productId: product.productId || '', | 
 |  |  |       product: product.product || product.productName || '', | 
 |  |  |       specificationId: product.specificationId || '', | 
 |  |  |       specification: product.specification || '', | 
 |  |  |       quantity: product.quantity || 0, | 
 |  |  |       unit: product.unit || '', | 
 |  |  |       unitPrice: product.unitPrice || 0, | 
 |  |  |       amount: product.amount || 0 | 
 |  |  |     })) : [], | 
 |  |  |     totalAmount: row.totalAmount || 0 | 
 |  |  |   } | 
 |  |  |   viewDialogVisible.value = true | 
 |  |  | } | 
 |  |  |  | 
 |  |  | 
 |  |  |   dialogTitle.value = '编辑报价' | 
 |  |  |   isEdit.value = true | 
 |  |  |   editId.value = row.id | 
 |  |  |   Object.assign(form, row) | 
 |  |  |   // 只复制需要的字段,避免将组件引用放入响应式对象 | 
 |  |  |   form.quotationNo = row.quotationNo || '' | 
 |  |  |   form.customer = row.customer || '' | 
 |  |  |   form.salesperson = row.salesperson || '' | 
 |  |  |   form.quotationDate = row.quotationDate || '' | 
 |  |  |   form.validDate = row.validDate || '' | 
 |  |  |   form.paymentMethod = row.paymentMethod || '' | 
 |  |  |   form.deliveryPeriod = row.deliveryPeriod || '' | 
 |  |  |   form.status = row.status || '草稿' | 
 |  |  |   form.remark = row.remark || '' | 
 |  |  |   form.products = row.products ? row.products.map(product => ({ | 
 |  |  |     productId: product.productId || '', | 
 |  |  |     product: product.product || product.productName || '', | 
 |  |  |     specificationId: product.specificationId || '', | 
 |  |  |     specification: product.specification || '', | 
 |  |  |     quantity: product.quantity || 0, | 
 |  |  |     unit: product.unit || '', | 
 |  |  |     unitPrice: product.unitPrice || 0, | 
 |  |  |     amount: product.amount || 0 | 
 |  |  |   })) : [] | 
 |  |  |   form.subtotal = row.subtotal || 0 | 
 |  |  |   form.freight = row.freight || 0 | 
 |  |  |   form.otherFee = row.otherFee || 0 | 
 |  |  |   form.discountRate = row.discountRate || 0 | 
 |  |  |   form.discountAmount = row.discountAmount || 0 | 
 |  |  |   form.totalAmount = row.totalAmount || 0 | 
 |  |  |   dialogVisible.value = true | 
 |  |  | } | 
 |  |  |  | 
 |  |  | 
 |  |  |  | 
 |  |  | const addProduct = () => { | 
 |  |  |   form.products.push({ | 
 |  |  |     productId: '', | 
 |  |  |     product: '', | 
 |  |  |     productName: '', | 
 |  |  |     specificationId: '', | 
 |  |  |     specification: '', | 
 |  |  |     quantity: 1, | 
 |  |  |     unit: '', | 
 |  |  | 
 |  |  |   getQuotationList(params).then(res=>{ | 
 |  |  |     // console.log(res) | 
 |  |  |     if(res.code===200){ | 
 |  |  |       quotationList.value = res.data.records | 
 |  |  |       // 只复制需要的字段,避免将组件引用或其他对象放入响应式对象 | 
 |  |  |       quotationList.value = (res.data.records || []).map(item => ({ | 
 |  |  |         id: item.id, | 
 |  |  |         quotationNo: item.quotationNo || '', | 
 |  |  |         customer: item.customer || '', | 
 |  |  |         salesperson: item.salesperson || '', | 
 |  |  |         quotationDate: item.quotationDate || '', | 
 |  |  |         validDate: item.validDate || '', | 
 |  |  |         paymentMethod: item.paymentMethod || '', | 
 |  |  |         deliveryPeriod: item.deliveryPeriod || '', | 
 |  |  |         status: item.status || '草稿', | 
 |  |  |         remark: item.remark || '', | 
 |  |  |         products: item.products ? item.products.map(product => ({ | 
 |  |  |           productId: product.productId || '', | 
 |  |  |           product: product.product || product.productName || '', | 
 |  |  |           specificationId: product.specificationId || '', | 
 |  |  |           specification: product.specification || '', | 
 |  |  |           quantity: product.quantity || 0, | 
 |  |  |           unit: product.unit || '', | 
 |  |  |           unitPrice: product.unitPrice || 0, | 
 |  |  |           amount: product.amount || 0 | 
 |  |  |         })) : [], | 
 |  |  |         subtotal: item.subtotal || 0, | 
 |  |  |         freight: item.freight || 0, | 
 |  |  |         otherFee: item.otherFee || 0, | 
 |  |  |         discountRate: item.discountRate || 0, | 
 |  |  |         discountAmount: item.discountAmount || 0, | 
 |  |  |         totalAmount: item.totalAmount || 0 | 
 |  |  |       })) | 
 |  |  |       pagination.total = res.data.total | 
 |  |  |     } | 
 |  |  |   }) | 
 |  |  |     customerList().then((res) => { | 
 |  |  |         customerOption.value = res; | 
 |  |  |         // 只复制需要的字段,避免将组件引用放入响应式对象 | 
 |  |  |         customerOption.value = (Array.isArray(res) ? res : []).map(item => ({ | 
 |  |  |       id: item.id, | 
 |  |  |       customerName: item.customerName || '', | 
 |  |  |       taxpayerIdentificationNumber: item.taxpayerIdentificationNumber || '' | 
 |  |  |     })) | 
 |  |  |     }); | 
 |  |  | } | 
 |  |  |  |