| | |
| | | </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 || '' |
| | | })) |
| | | }); |
| | | } |
| | | |