@ -2,19 +2,19 @@
< div class = "buy-module" >
< div class = "header-tools" >
< div class = "left-actions" >
< el-button type = "primary" :icon = "Plus" @click ="handleCreate" > 全量 采购入库登记 < / el -button >
< el-button :icon = "Refresh" @click ="fetchData" > 刷新数据 < / el -button >
< el-button type = "primary" :icon = "Plus" @click ="handleCreate" class = "big-font-btn" > 采购入库登记 < / el-button>
< el-button :icon = "Refresh" @click ="fetchData" class = "big-font-btn" > 刷新数据 < / el-button>
< / div >
< el-popover placement = "bottom" title = "显示列配置" :width = "400" trigger = "click" >
< template # reference >
< el-button :icon = "Setting" > 自定义表格表头 < / el-button >
< el-button :icon = "Setting" class = "big-font-btn" > 自定义表格表头 < / el-button >
< / template >
< el-checkbox-group v-model = "visibleColumnProps" class="column-selector" >
< el -divider content -position = " left " > 基础层字段 < / el-divider >
< el-checkbox v-for = "c in baseColumns" :key="c.prop" :value ="c.prop" > {{ c.label }} < / el -checkbox >
< el-checkbox v-for = "c in baseColumns" :key="c.prop" :label ="c.prop" > {{ c.label }} < / el -checkbox >
< el-divider content -position = " left " > 库存 / 财务层字段 < / el-divider >
< el-checkbox v-for = "c in stockColumns" :key="c.prop" :value ="c.prop" > {{ c.label }} < / el -checkbox >
< el-checkbox v-for = "c in stockColumns" :key="c.prop" :label ="c.prop" > {{ c.label }} < / el -checkbox >
< / el-checkbox-group >
< / el-popover >
< / div >
@ -25,15 +25,16 @@
border
stripe
style = "width: 100%"
size = "small "
size = "default "
highlight -current -row
class = "custom-big-table"
>
< template v-for = "col in allColumns" :key="col.prop" >
< el -table -column
v-if = "visibleColumnProps.includes(col.prop)"
:prop = "col.prop"
:label = "col.label"
: min -width = " col.minWidth | | ' 12 0 ' "
: min -width = " col.minWidth | | ' 15 0 ' "
show -overflow -tooltip
>
< template # default = "scope" v-if = "col.prop === 'serial_batch'" >
@ -47,23 +48,23 @@
< / template >
< template # default = "scope" v-else-if = "col.prop === 'status'" >
< el -tag size = "small " :type = "getStatusType(scope.row.status)" >
< el -tag size = "large " :type = "getStatusType(scope.row.status)" style = "font-size: 18px;" >
{ { scope . row . status } }
< / el-tag >
< / template >
< template # default = "scope" v-else-if = "['unit_price', 'total_price '].includes(col.prop)" >
< template # default = "scope" v-else-if = "['price_unit', 'price_total '].includes(col.prop)" >
{{ formatMoney ( scope.row [ col.prop ] ) }}
< / template >
< / el -table -column >
< / template >
< el-table-column label = "操作" width = "15 0" fixed = "right" align = "center" >
< el-table-column label = "操作" width = "20 0" fixed = "right" align = "center" >
< template # default = "{ row }" >
< el-button link type = "primary" size = "small " @click ="handleUpdate(row)" > 编辑 < / el -button >
< el-button link type = "primary" size = "large " @click ="handleUpdate(row)" style = "font-size: 15px;" > 编辑 < / el-button>
< el-popconfirm title = "确定删除该条入库记录吗?" @confirm ="handleDelete(row)" >
< template # reference >
< el-button link type = "danger" size = "small " > 删除 < / el-button >
< el-button link type = "danger" size = "large" style = "font-size: 15px; " > 删除 < / el-button >
< / template >
< / el-popconfirm >
< / template >
@ -89,7 +90,7 @@
destroy -on -close
:close-on-click-modal = "false"
>
< el-form :model = "form" label -width = " 12 0px " ref = "formRef" :rules = "rules" size = "default " >
< el-form :model = "form" label -width = " 14 0px " ref = "formRef" :rules = "rules" size = "large " >
< el-divider content -position = " left " > < b > 1. 基础核心层 ( Material Base ) < / b > < / el-divider >
< el-row :gutter = "20" >
@ -113,7 +114,11 @@
< el-divider content -position = " left " > < b > 2. 实体库存层 ( Stock Buy ) < / b > < / el-divider >
< el-row :gutter = "20" >
< el-col :span = "8" > < el-form-item label = "编码/SKU" prop = "sku" > < el-input v-model = "form.sku" placeholder="选填" / > < / el-form-item > < / el-col >
< el-col :span = "8" >
< el-form-item label = "编码/SKU" prop = "sku" >
< el-input v-model = "form.sku" placeholder="选填" / >
< / el-form-item >
< / el-col >
< el-col :span = "8" >
< el-form-item label = "入库日期" prop = "in_date" >
< el-input v-model = "form.in_date" disabled placeholder="系统自动生成" >
@ -121,7 +126,11 @@
< / el-input >
< / el-form-item >
< / el-col >
< el-col :span = "8" > < el-form-item label = "库位" prop = "warehouse_location" > < el-input v-model = "form.warehouse_location" / > < / el-form-item > < / el-col >
< el-col :span = "8" >
< el-form-item label = "库位" prop = "warehouse_location" >
< el-input v-model = "form.warehouse_location" / >
< / el-form-item >
< / el-col >
< / el-row >
< el-row :gutter = "20" style = "background-color: #fffbf0; border-radius: 4px; padding-top:10px;" >
@ -136,7 +145,7 @@
< / el-form-item >
< / el-col >
< el-col :span = "24" >
< div style = "font-size: 12 px; color: #e6a23c; margin-left: 12 0px; margin-bottom: 10px; line-height: 1;" >
< div style = "font-size: 14 px; color: #e6a23c; margin-left: 14 0px; margin-bottom: 10px; line-height: 1;" >
* 规则 : 序列号与批号互斥且必填其一 ( 填写一个会自动清空另一个 )
< / div >
< / el-col >
@ -185,8 +194,8 @@
< / el-form >
< template # footer >
< el-button @click ="visible = false" > 取消 < / el -button >
< el-button type = "primary" :loading = "submitting" @click ="submitForm" >
< el-button @click ="visible = false" style = "font-size: 15px;" > 取消 < / el-button>
< el-button type = "primary" :loading = "submitting" @click ="submitForm" style = "font-size: 15px;" >
{ { dialogStatus === 'create' ? '确认入库' : '保存修改' } }
< / el-button >
< / template >
@ -213,25 +222,24 @@ const queryParams = reactive({ page: 1, pageSize: 15 })
// --- 1. 列定义 ---
const baseColumns = [
{ prop : 'material_name' , label : '物料名称' , minWidth : '15 0' } ,
{ prop : 'category' , label : '类别' , minWidth : '10 0' } ,
{ prop : 'spec_model' , label : '规格型号' , minWidth : '15 0' } ,
{ prop : 'unit' , label : '单位' , minWidth : '7 0' }
{ prop : 'material_name' , label : '物料名称' , minWidth : '20 0' } ,
{ prop : 'category' , label : '类别' , minWidth : '12 0' } ,
{ prop : 'spec_model' , label : '规格型号' , minWidth : '20 0' } ,
{ prop : 'unit' , label : '单位' , minWidth : '10 0' }
]
const stockColumns = [
{ prop : 'sku' , label : '编码/SKU' , minWidth : '14 0' } ,
{ prop : 'inbound_date' , label : '入库日期' , minWidth : '12 0' } ,
// 组合展示列
{ prop : 'serial_batch ' , label : '序列号/批号 ' , minWidth : '16 0' } ,
{ prop : 'stock_quantity ' , label : '库存 数' , minWidth : '9 0' } ,
{ prop : 'available_quantity ' , label : '可用数 ' , minWidth : '9 0' } ,
{ prop : 'in_quant ity ' , label : '入库量 ' , minWidth : '9 0' } ,
{ prop : 'unit_ price' , label : '单 价' , minWidth : '11 0' } ,
{ prop : 'total_price ' , label : '总价 ' , minWidth : '11 0' } ,
{ prop : 'status ' , label : '状态 ' , minWidth : '9 0' } ,
{ prop : 'warehouse_location ' , label : '库位 ' , minWidth : '1 00' } ,
{ prop : 'supplier_name' , label : '供应商' , minWidth : '150' }
{ prop : 'sku' , label : '编码/SKU' , minWidth : '18 0' } ,
{ prop : 'inbound_date' , label : '入库日期' , minWidth : '16 0' } ,
{ prop : 'serial_batch' , label : '序列号/批号' , minWidth : '220' } ,
{ prop : 'qty_stock ' , label : '库存数 ' , minWidth : '12 0' } ,
{ prop : 'qty_available ' , label : '可用 数' , minWidth : '12 0' } ,
{ prop : 'qty_inbound ' , label : '入库量 ' , minWidth : '12 0' } ,
{ prop : 'price_un it' , label : '单价 ' , minWidth : '15 0' } ,
{ prop : 'price_total ' , label : '总 价' , minWidth : '15 0' } ,
{ prop : 'status ' , label : '状态 ' , minWidth : '12 0' } ,
{ prop : 'warehouse_loc ' , label : '库位 ' , minWidth : '15 0' } ,
{ prop : 'supplier_name ' , label : '供应商 ' , minWidth : '2 00' }
]
const allColumns = [ ... baseColumns , ... stockColumns ]
@ -239,12 +247,12 @@ const allColumns = [...baseColumns, ...stockColumns]
// --- 2. 默认展示列 ---
const visibleColumnProps = ref ( [
'material_name' , 'spec_model' , 'inbound_date' ,
'serial_batch' , 'stock_quantity ' , 'available_quantity ' , 'status'
'serial_batch' , 'qty_ stock' , 'qty_ available' , 'status'
] )
// --- 3. 表单对象 ---
const form = reactive ( {
id : undefined , // 编辑时使用
id : undefined ,
material _name : '' , category : '' , spec _model : '' , unit : '个' ,
material _type : '采购件' , visibility _level : 0 ,
sku : '' , in _date : '' ,
@ -255,12 +263,11 @@ const form = reactive({
supplier _name : '' , arrival _photo : '' , remark : ''
} )
// --- 4. 校验逻辑 (互斥且必填其一) ---
// --- 4. 校验逻辑 ---
const validateIdentity = ( rule : any , value : any , callback : any ) => {
if ( ! form . serial _number && ! form . batch _number ) {
callback ( new Error ( '序列号和批号至少填写一项' ) )
} else {
// 清除交叉报错
if ( formRef . value ) {
if ( rule . field === 'serial_number' && form . batch _number ) formRef . value . clearValidate ( 'batch_number' )
if ( rule . field === 'batch_number' && form . serial _number ) formRef . value . clearValidate ( 'serial_number' )
@ -278,12 +285,8 @@ const rules = {
}
// --- 5. 监听逻辑 ---
watch ( ( ) => form . serial _number , ( val ) => {
if ( val && form . batch _number ) form . batch _number = ''
} )
watch ( ( ) => form . batch _number , ( val ) => {
if ( val && form . serial _number ) form . serial _number = ''
} )
watch ( ( ) => form . serial _number , ( val ) => { if ( val && form . batch _number ) form . batch _number = '' } )
watch ( ( ) => form . batch _number , ( val ) => { if ( val && form . serial _number ) form . serial _number = '' } )
watch ( ( ) => form . in _quantity , ( newVal ) => {
if ( newVal !== undefined ) {
@ -297,16 +300,15 @@ watch(() => form.in_quantity, (newVal) => {
watch ( ( ) => form . unit _price , ( newVal ) => {
if ( newVal !== undefined ) {
form . total _price = Number ( ( newVal * form . in _quantity ) . toFixed ( 4 ) )
form . total _price = Number ( ( newVal * ( form . in _quantity || 0 ) ) . toFixed ( 4 ) )
}
} )
// --- 6. 核心操作 ---
const fetchData = async ( ) => {
loading . value = true
try {
const res = await getBuyList ( queryParams )
const res : any = await getBuyList ( queryParams )
tableData . value = res . data . items || [ ]
total . value = res . data . total || 0
} finally { loading . value = false }
@ -319,33 +321,27 @@ const handleCreate = () => {
visible . value = true
}
// 核心修改:手动映射后端数据到前端表单
const handleUpdate = ( row : any ) => {
dialogStatus . value = 'update'
// 先重置表单防止残留
resetForm ( )
// 1. 基础字段拷贝
Object . assign ( form , row )
// 2. 修正字段映射 (后端Key -> 前端Form Key)
form . id = row . id
form . in _quantity = Number ( row . qty _inbound ) || 1
form . stock _quantity = Number ( row . qty _inbound ) || 1 // 这里假设库存没变, 或者应由后端传回stock_quantity
form . available _quantity = Number ( row . qty _available ) || 1
form . material _name = row . material _name
form . spec _model = row . spec _model
form . category = row . category
form . unit = row . unit
form . sku = row . sku
form . in _date = row . inbound _date
form . in _quantity = Number ( row . qty _inbound ) || 0
form . stock _quantity = Number ( row . qty _stock ) || 0
form . available _quantity = Number ( row . qty _available ) || 0
form . unit _price = Number ( row . price _unit ) || 0
form . total _price = Number ( row . price _total ) || 0
form . warehouse _location = row . warehouse _loc || ''
form . serial _number = row . serial _number || ''
form . batch _number = row . batch _number || ''
form . supplier _name = row . supplier _name || ''
form . status = row . status || '在库'
// 3. 计算总价
form . total _price = Number ( ( form . in _quantity * form . unit _price ) . toFixed ( 2 ) )
// 4. 补充日期
if ( ! form . in _date ) form . in _date = dayjs ( ) . format ( 'YYYY-MM-DD HH:mm:ss' )
form . remark = row . remark || ''
visible . value = true
}
@ -355,7 +351,7 @@ const handleDelete = async (row: any) => {
ElMessage . success ( '删除成功' )
fetchData ( )
} catch ( e : any ) {
ElMessage . error ( e . message || '删除失败' )
ElMessage . error ( '删除失败' )
}
}
@ -375,7 +371,7 @@ const submitForm = async () => {
visible . value = false
fetchData ( )
} catch ( e : any ) {
ElMessage . error ( e . message || '提交失败' )
ElMessage . error ( '提交失败' )
} finally { submitting . value = false }
}
} )
@ -399,17 +395,27 @@ const getStatusType = (status: string) => {
return status === '在库' ? 'success' : 'info'
}
const formatMoney = ( val : number ) => {
return val ? ` ¥ ${ Number ( val ) . toFixed ( 2 ) } ` : '-'
const formatMoney = ( val : any ) => {
const num = Number ( val )
return isNaN ( num ) ? '-' : ` ¥ ${ num . toFixed ( 2 ) } `
}
onMounted ( ( ) => fetchData ( ) )
< / script >
< style scoped >
. buy - module { background : # fff ; border - radius : 8 px ; }
. buy - module { background : # fff ; border - radius : 8 px ; padding : 15 px ; }
. header - tools { display : flex ; justify - content : space - between ; align - items : center ; margin - bottom : 15 px ; }
. column - selector { display : flex ; flex - direction : column ; padding : 10 px ; max - height : 400 px ; overflow - y : auto ; }
. pagination - container { margin - top : 20 px ; display : flex ; justify - content : flex - end ; }
. pagination - container { margin - top : 15 px ; display : flex ; justify - content : flex - end ; }
: deep ( . el - divider -- horizontal ) { margin : 15 px 0 15 px 0 ; }
. custom - big - table { font - size : 15 px ! important ; }
: deep ( . el - table . el - table _ _cell ) { padding : 12 px 0 ; }
: deep ( . el - table th . cell ) { font - size : 22 px ; font - weight : bold ; }
: deep ( . el - table td . cell ) { line - height : 1.5 ; font - size : 15 px ; }
. big - font - btn { font - size : 15 px ! important ; padding : 15 px 25 px ! important ; }
: deep ( . el - form - item _ _label ) { font - size : 15 px ! important ; }
: deep ( . el - input _ _inner ) { font - size : 15 px ! important ; height : 45 px ; }
: deep ( . el - divider _ _text ) { font - size : 15 px ! important ; }
< / style >