| | |
| | | <div class="product-info"> |
| | | <div class="product-name">{{ row.productName }}</div> |
| | | <div class="product-spec">{{ row.specification }}</div> |
| | | <div class="product-code">编码: {{ row.productCode }}</div> |
| | | <!-- <div class="product-code">编码: {{ row.productCode }}</div> --> |
| | | </div> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="供应商" prop="supplierName" width="150" /> |
| | | <el-table-column label="供应商" prop="supplierName" width="200" /> |
| | | <el-table-column label="基础价格" width="120" align="right"> |
| | | <template #default="{ row }"> |
| | | <span class="price-text">¥{{ row.basePrice }}</span> |
| | |
| | | <el-table-column label="状态" width="100" align="center"> |
| | | <template #default="{ row }"> |
| | | <el-tag :type="getStatusType(row.status)">{{ getStatusText(row.status) }}</el-tag> |
| | | <div v-if="isPriceWarning(row)" class="warning-indicator"> |
| | | <!-- <div v-if="isPriceWarning(row)" class="warning-indicator"> |
| | | <el-icon color="#F56C6C"><Warning /></el-icon> |
| | | </div> |
| | | </div> --> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="生效时间" prop="effectiveTime" width="180" /> |
| | |
| | | <el-form :model="formData" :rules="formRules" ref="formRef" label-width="120px"> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="商品名称" prop="productName"> |
| | | <el-select v-model="formData.productName" placeholder="请选择商品" style="width: 100%" filterable> |
| | | <el-option v-for="product in productList" :key="product.id" :label="product.name" :value="product.name" /> |
| | | </el-select> |
| | | <el-form-item label="商品名称" prop="productId"> |
| | | <el-tree-select |
| | | v-model="formData.productId" |
| | | placeholder="请选择商品" |
| | | clearable |
| | | filterable |
| | | check-strictly |
| | | @change="getModels" |
| | | :data="productOptions" |
| | | :props="{ label: 'productName', value: 'id', children: 'children' }" |
| | | node-key="id" |
| | | :render-after-expand="false" |
| | | style="width: 100%" |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | |
| | | <el-row :gutter="20"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="规格型号" prop="specification"> |
| | | <el-input v-model="formData.specification" placeholder="请输入规格型号" /> |
| | | <el-select |
| | | v-model="formData.specification" |
| | | placeholder="请选择" |
| | | clearable |
| | | @change="getProductModel" |
| | | > |
| | | <el-option |
| | | v-for="item in modelOptions" |
| | | :key="item.id" |
| | | :label="item.model" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="12"> |
| | | <el-form-item label="供应商" prop="supplierName"> |
| | | <el-select v-model="formData.supplierName" placeholder="请选择供应商" style="width: 100%"> |
| | | <el-option v-for="supplier in supplierList" :key="supplier.id" :label="supplier.name" :value="supplier.name" /> |
| | | <el-form-item label="供应商" prop="supplierId"> |
| | | <el-select |
| | | v-model="formData.supplierId" |
| | | placeholder="请选择供应商" |
| | | clearable |
| | | @change="handleSupplierChange" |
| | | > |
| | | <el-option |
| | | v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id" |
| | | /> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <!-- 折扣设置 --> |
| | | <el-divider content-position="left">折扣设置</el-divider> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="折扣类型"> |
| | | <el-select v-model="formData.discountType" placeholder="请选择折扣类型" style="width: 100%"> |
| | | <el-option label="无折扣" value="" /> |
| | |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="折扣值" v-if="formData.discountType && formData.discountType !== 'tiered'"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="折扣值"> |
| | | <el-input-number |
| | | v-model="formData.discountValue" |
| | | :disabled="!(formData.discountType && formData.discountType !== 'tiered')" |
| | | :min="0" |
| | | :max="formData.discountType === 'percentage' ? 100 : undefined" |
| | | :precision="2" |
| | |
| | | /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="折扣有效期"> |
| | | <el-date-picker |
| | | v-model="formData.discountEndTime" |
| | | :disabled="!(formData.discountType && formData.discountType !== 'tiered')" |
| | | type="datetime" |
| | | placeholder="选择结束时间" |
| | | style="width: 100%" |
| | |
| | | <!-- 价格控制 --> |
| | | <el-divider content-position="left">价格控制</el-divider> |
| | | <el-row :gutter="20"> |
| | | <el-col :span="8"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="最低价格"> |
| | | <el-input-number v-model="formData.minPrice" :min="0" :precision="2" placeholder="最低价格" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-col :span="12"> |
| | | <el-form-item label="最高价格"> |
| | | <el-input-number v-model="formData.maxPrice" :min="0" :precision="2" placeholder="最高价格" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | <el-col :span="8"> |
| | | <el-form-item label="预警阈值(%)"> |
| | | <el-input-number v-model="formData.warningThreshold" :min="0" :max="100" :precision="1" placeholder="预警阈值" style="width: 100%" /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | <script setup> |
| | | import {ref, reactive, computed, onMounted, getCurrentInstance} from 'vue' |
| | | import { ElMessage, ElMessageBox } from 'element-plus' |
| | | import { productTreeList, modelList } from "@/api/basicData/product.js"; |
| | | import { |
| | | Search, Refresh, Plus, Discount, Setting, Download, Delete, Edit, |
| | | Warning |
| | | } from '@element-plus/icons-vue' |
| | | import { listPage, update, del, add } from '@/api/procurementManagement/advancedPriceManagement' |
| | | |
| | | import { |
| | | getOptions, |
| | | } from "@/api/procurementManagement/procurementLedger.js"; |
| | | // 响应式数据 |
| | | const loading = ref(false) |
| | | const submitLoading = ref(false) |
| | |
| | | const batchDiscountVisible = ref(false) |
| | | const priceControlVisible = ref(false) |
| | | const dialogType = ref('add') |
| | | const productOptions = ref([]); |
| | | const modelOptions = ref([]); |
| | | const selectedRows = ref([]) |
| | | const formRef = ref() |
| | | |
| | |
| | | |
| | | // 表单数据 |
| | | const formData = reactive({ |
| | | productId: null, |
| | | productName: '', |
| | | productCode: '', |
| | | specification: '', |
| | | supplierId: null, |
| | | supplierName: '', |
| | | specificationId: null, |
| | | basePrice: 0, |
| | | unit: '', |
| | | discountType: '', |
| | |
| | | |
| | | // 表单验证规则 |
| | | const formRules = { |
| | | productName: [{ required: true, message: '请选择商品名称', trigger: 'change' }], |
| | | productId: [{ required: true, message: '请选择商品名称', trigger: 'change' }], |
| | | productCode: [{ required: true, message: '请输入商品编码', trigger: 'blur' }], |
| | | supplierName: [{ required: true, message: '请选择供应商', trigger: 'change' }], |
| | | supplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }], |
| | | basePrice: [{ required: true, message: '请输入基础价格', trigger: 'blur' }], |
| | | effectiveTime: [{ required: true, message: '请选择生效时间', trigger: 'change' }], |
| | | reason: [{ required: true, message: '请选择调价原因', trigger: 'change' }] |
| | | } |
| | | |
| | | getOptions().then((res) => { |
| | | supplierList.value = res.data; |
| | | }); |
| | | |
| | | const supplierList = ref([ |
| | | { id: 1, name: '优质五金供应商' }, |
| | |
| | | } else if (row.discountType === 'fixed') { |
| | | finalPrice = row.basePrice - row.discountValue |
| | | } |
| | | return Math.max(finalPrice, 0) |
| | | let man = Math.max(finalPrice, 0) |
| | | return man.toFixed(2) |
| | | } |
| | | |
| | | const getDiscountTagType = (discountType) => { |
| | |
| | | return textMap[discountType] || '未知' |
| | | } |
| | | |
| | | const getProductOptions = () => { |
| | | productTreeList().then((res) => { |
| | | productOptions.value = res; |
| | | }); |
| | | }; |
| | | |
| | | const findNodeById = (data, id) => { |
| | | for (const item of data) { |
| | | if (item.id === id) return item; |
| | | if (item.children) { |
| | | const found = findNodeById(item.children, id); |
| | | if (found) return found; |
| | | } |
| | | } |
| | | return null; |
| | | }; |
| | | |
| | | const getModels = (value) => { |
| | | if (value) { |
| | | const selectedProduct = findNodeById(productOptions.value, value); |
| | | if (selectedProduct) { |
| | | formData.productName = selectedProduct.productName; |
| | | formData.productCode = selectedProduct.productCode; |
| | | } |
| | | modelList({ id: value }).then((res) => { |
| | | modelOptions.value = res; |
| | | }); |
| | | } else { |
| | | formData.productName = ""; |
| | | formData.productCode = ""; |
| | | modelOptions.value = []; |
| | | } |
| | | }; |
| | | |
| | | const getStatusType = (status) => { |
| | | const statusMap = { |
| | | active: 'success', |
| | |
| | | expired: 'info' |
| | | } |
| | | return statusMap[status] || 'info' |
| | | } |
| | | |
| | | const getProductModel = (value) => { |
| | | const index = modelOptions.value.findIndex((item) => item.id === value); |
| | | if (index !== -1) { |
| | | formData.specification = modelOptions.value[index].model; |
| | | formData.specificationId = modelOptions.value[index].id; |
| | | formData.unit = modelOptions.value[index].unit; |
| | | } else { |
| | | formData.specification = null; |
| | | formData.specificationId = null; |
| | | formData.unit = null; |
| | | } |
| | | }; |
| | | |
| | | const handleSupplierChange = (value) => { |
| | | const supplier = supplierList.value.find(supplier => supplier.id === value) |
| | | if (supplier) { |
| | | formData.supplierId = supplier.id |
| | | formData.supplierName = supplier.supplierName |
| | | } |
| | | } |
| | | |
| | | const getStatusText = (status) => { |
| | |
| | | } |
| | | return statusMap[status] || '未知' |
| | | } |
| | | |
| | | const isPriceWarning = (row) => { |
| | | if (!row.priceControl) return false |
| | | const finalPrice = calculateFinalPrice(row) |
| | | return finalPrice < row.priceControl.minPrice || finalPrice > row.priceControl.maxPrice |
| | | } |
| | | |
| | | |
| | | const handleSearch = () => { |
| | | loading.value = true |
| | |
| | | const openDialog = (type, row = {}) => { |
| | | dialogType.value = type |
| | | if (type === 'edit' && row.id) { |
| | | // 复制行数据到表单 |
| | | Object.assign(formData, { |
| | | ...row, |
| | | minPrice: row.priceControl?.minPrice, |
| | | maxPrice: row.priceControl?.maxPrice, |
| | | // 兼容两种数据结构:平铺的字段或嵌套在 priceControl 中的字段 |
| | | minPrice: row.minPrice ?? row.priceControl?.minPrice, |
| | | maxPrice: row.maxPrice ?? row.priceControl?.maxPrice, |
| | | // 确保折扣有效期也被赋值 (如果 row.discountEndTime 存在的话) |
| | | discountEndTime: row.discountEndTime || row.discountEndTime, |
| | | tieredDiscount: row.tieredDiscount || [] |
| | | }) |
| | | } else { |
| | |
| | | |
| | | const resetFormData = () => { |
| | | Object.assign(formData, { |
| | | productId: null, |
| | | productName: '', |
| | | productCode: '', |
| | | specification: '', |
| | | supplierId: null, |
| | | supplierName: '', |
| | | basePrice: 0, |
| | | unit: '', |
| | |
| | | }) |
| | | } |
| | | |
| | | const removeTieredRow = (index) => { |
| | | formData.tieredDiscount.splice(index, 1) |
| | | } |
| | | |
| | | const handleSubmit = async () => { |
| | | if (!formRef.value) return |
| | | formData.actualPrice = calculateFinalPrice(formData) |
| | | if( formData.discountType === ''){ |
| | | formData.discountEndTime = '2099-12-31 23:59:59' |
| | | } |
| | | |
| | | try { |
| | | await formRef.value.validate() |
| | |
| | | // 生命周期 |
| | | onMounted(() => { |
| | | handleSearch() |
| | | getProductOptions() |
| | | }) |
| | | </script> |
| | | |