@@ -8,7 +8,7 @@
/ >
<!-- 表单区域 -- >
< view class = "pb-180rpx" >
< view >
< wd-form ref = "formRef" :model = "formData" :rules = "formRules" >
< wd-cell-group title = "基本信息" border >
< wd-cell title = "请购单号" : value = "formData.no || '保存时自动生成'" / >
@@ -16,6 +16,7 @@
title = "请购类型"
title -width = " 180rpx "
is -link
center
:value = "getTypeLabel(formData.type)"
@click ="typePickerVisible = true"
/ >
@@ -23,6 +24,7 @@
title = "优先级"
title -width = " 180rpx "
is -link
center
:value = "getPriorityLabel(formData.priority)"
@click ="priorityPickerVisible = true"
/ >
@@ -30,6 +32,7 @@
title = "紧急程度"
title -width = " 180rpx "
is -link
center
:value = "getEmergencyLabel(formData.emergencyDegree)"
@click ="emergencyPickerVisible = true"
/ >
@@ -37,6 +40,7 @@
title = "请购时间"
title -width = " 180rpx "
is -link
center
: value = "formData.requestTime ? formatDate(formData.requestTime) : '请选择'"
@click ="requestDatePickerVisible = true"
/ >
@@ -44,6 +48,7 @@
title = "期望到货"
title -width = " 180rpx "
is -link
center
: value = "formData.expectedTime ? formatDate(formData.expectedTime) : '请选择'"
@click ="expectedDatePickerVisible = true"
/ >
@@ -57,109 +62,142 @@
clearable
/ >
< / wd-cell-group >
< / wd-form >
< / view >
<!-- 请购产品清单 -- >
< wd-cell-group title = "请购产品清单" border >
< view v-if = "formData.items.length === 0" class="py-40rpx text-center text-[#999]" >
暂无产品 , 请点击下方按钮添加
< view class = "mx-24rpx mt-24rpx pb-180rpx" >
< view class = "mb-16rpx flex items-center justify-between" >
< view class = "text-32rpx text-[#333] font-semibold" >
请购产品清单 ( { { formData . items ? . length || 0 } } 项 )
< / view >
< wd-button size = "small" type = "primary" @click ="handleAddItem" >
+ 添加产品
< / wd -button >
< / view >
< view v-else >
< view
v-for = "(item, index) in formData.items"
:key = "index"
class = "mx-24rpx mb-20rpx rounded-12rpx bg-[#f9f9f9] p-24rpx "
class = "mb-16rpx overflow-hidden rounded-12rpx bg-white shadow-sm "
>
< view class = "mb-12rpx flex items-center justify-between" >
< view class = "text-28rpx text-[#333] font-semibold" >
{ { item . productName || '请选择产品' } }
< / view >
< wd-icon name = "delete" size = "40rpx" color = "#f56c6c" @click ="removeItem(index)" / >
< / view >
< view class = "mb-12rpx" >
< wd-cell
title = "产品"
title -width = " 140rpx "
is -link
: value = "item.productName || '请选择'"
@click ="openProductPicker(index)"
/ >
< / view >
< view class = "mb-12rpx" >
< wd-input
v-model = "item.count"
label = "需求数量"
label -width = " 140rpx "
type = "number"
placeholder = "请输入数量"
@change ="calcItemTotal(item)"
/ >
< / view >
< view class = "mb-12rpx" >
< wd-input
v-model = "item.productPrice"
label = "参考单价"
label -width = " 140rpx "
type = "digit"
placeholder = "请输入单价"
@change ="calcItemTotal(item)"
/ >
< / view >
< view class = "mb-12rpx flex items-center justify-between text-26rpx" >
< text class = "text-[#999]" > 产品金额 < / text >
< text class = "text-[#666]" > { { formatPrice ( item . totalProductPrice ) } } < / text >
< / view >
< view class = "mb-12rpx" >
< wd-input
v-model = "item.taxPercent"
label = "税率(%)"
label -width = " 140rpx "
type = "digit"
placeholder = "请输入税率"
@change ="calcItemTotal(item)"
/ >
< / view >
< view class = "mb-12rpx flex items-center justify-between text-26rpx" >
< text class = "text-[#999]" > 税额 < / text >
< text class = "text-[#666]" > { { formatPrice ( item . taxPrice ) } } < / text >
< / view >
< view class = "mb-12rpx flex items-center justify-between text-26rpx" >
< text class = "text-[#999]" > 含税金额 < / text >
< text class = "text-[#1890ff] font-semibold" > { { formatPrice ( item . totalPrice ) } } < / text >
< / view >
< view class = "mb-12rpx" >
< wd-input
v-model = "item.purpose"
label = "用途说明"
label -width = " 140rpx "
placeholder = "请输入用途"
/ >
< / view >
< view class = "mb-12rpx" >
< wd-input
v-model = "item.remark"
label = "备注"
label -width = " 140rpx "
placeholder = "请输入备注"
/ >
< / view >
< / view >
< / view >
< view class = "px-24rpx pb-24rpx" >
< wd-button type = "primary" plain block @click ="addItem" >
< wd -icon name = "add" class = "mr-8rpx" / >
添加产品
< view class = "flex items-center justify-between bg-[#f8f8f8] px-24rpx py-12rpx " >
< text class = "text-28rpx text-[#333] font-semibold" > 产品 # { { index + 1 } } { { item . productName || '' } } < / text >
< wd-button size = "small" type = "error" plain @click ="handleRemoveItem(index)" >
删除
< / wd -button >
< / view >
< / wd-cell-group >
< view class = "p-24rpx" >
< view class = "mb-16rpx" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 选择产品 < / text >
< wd-picker
v-model = "item.productId"
:columns = "productColumns"
placeholder = "请选择产品"
@confirm ="(e: any) => onProductConfirm(e, index)"
/ >
< / view >
<!-- 自动填充的产品信息 ( 只读 ) -- >
< view v-if = "item.productId" class="mb-16rpx rounded-8rpx bg-[#f9f9f9] p-16rpx" >
< view class = "mb-8rpx flex justify-between text-24rpx" >
< text class = "text-[#999]" > 规格 < / text >
< text class = "text-[#333]" > { { item . productSpec || '-' } } < / text >
< / view >
< view class = "mb-8rpx flex justify-between text-24rpx" >
< text class = "text-[#999]" > 单位 < / text >
< text class = "text-[#333]" > { { item . productUnitName || '-' } } < / text >
< / view >
< view class = "mb-8rpx flex justify-between text-24rpx" >
< text class = "text-[#999]" > 条码 < / text >
< text class = "text-[#333]" > { { item . productBarCode || '-' } } < / text >
< / view >
< / view >
< view class = "mb-16rpx flex gap-16rpx" >
< view class = "flex-1" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 需求数量 < / text >
< wd-input
v-model = "item.count"
type = "number"
placeholder = "需求数量"
clearable
@change ="calcItemTotal(item)"
/ >
< / view >
< view class = "flex-1" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 参考单价 < / text >
< wd-input
v-model = "item.productPrice"
type = "number"
placeholder = "参考单价"
clearable
@change ="calcItemTotal(item)"
/ >
< / view >
< / view >
< view class = "mb-16rpx flex gap-16rpx" >
< view class = "flex-1" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 税率 ( % ) < / text >
< wd-input
v-model = "item.taxPercent"
type = "number"
placeholder = "税率"
clearable
@change ="calcItemTotal(item)"
/ >
< / view >
< view class = "flex-1" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 含税金额 < / text >
< text class = "block pt-16rpx text-28rpx text-[#1890ff] font-semibold" > { { formatPrice ( item . totalPrice ) } } < / text >
< / view >
< / view >
< view class = "mb-16rpx flex gap-16rpx text-24rpx text-[#999]" >
< view class = "flex-1" >
< text > 产品金额 : { { formatPrice ( item . totalProductPrice ) } } < / text >
< / view >
< view class = "flex-1" >
< text > 税额 : { { formatPrice ( item . taxPrice ) } } < / text >
< / view >
< / view >
< view class = "mb-16rpx" >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 用途说明 < / text >
< wd-input
v-model = "item.purpose"
placeholder = "请输入用途"
clearable
/ >
< / view >
< view >
< text class = "mb-8rpx block text-24rpx text-[#999]" > 备注 < / text >
< wd-input
v-model = "item.remark"
placeholder = "请输入备注"
clearable
/ >
< / view >
< / view >
< / view >
< view v-if = "!formData.items?.length" class="py-60rpx text-center text-28rpx text-[#999]" >
暂无产品 , 请点击 " 添加产品 " 按钮
< / view >
< ! - - 合计信息 - - >
< wd-cell-group title = "合计信息" border >
< wd-cell title = "合计数量" :value = "formatCount(totalCount)" / >
< wd-cell title = "合计产品金额" :value = "formatPrice(totalProductPrice)" / >
< wd-cell title = "合计税额" :value = "formatPrice(totalTaxPrice)" / >
< wd-cell title = "合计金额(含税)" :value = "formatPrice(totalPrice)" / >
< / wd-cell-group >
< / wd-form >
< view v-if = "formData.items?.length" class="mt-24rpx rounded-12rpx bg-white p-24rpx shadow-sm" >
< view class = "mb-12rpx flex justify-between text-28rpx" >
< text class = "text-[#999]" > 合计数量 < / text >
< text class = "text-[#333]" > { { formatCount ( totalCount ) } } < / text >
< /view >
< view class = "mb-12rpx flex justify-between text-28rpx" >
< text class = "text-[#999]" > 合计产品金额 < / text >
< text class = "text-[#333]" > { { formatPrice ( totalProductPrice ) } } < / text >
< / view >
< view class = "mb-12rpx flex justify-between text-28rpx" >
< text class = "text-[#999]" > 合计税额 < / text >
< text class = "text-[#333]" > { { formatPrice ( totalTaxPrice ) } } < / text >
< / view >
< view class = "flex justify-between text-28rpx" >
< text class = "text-[#999]" > 合计金额 ( 含税 ) < / text >
< text class = "text-[#1890ff] font-semibold" > { { formatPrice ( totalPrice ) } } < / text >
< / view >
< / view >
< / view >
<!-- 底部保存按钮 -- >
@@ -210,19 +248,13 @@
:value = "formData.expectedTime"
@confirm ="onExpectedDateConfirm"
/ >
<!-- 产品选择器 -- >
< wd-picker
v-model = "productPickerVisible"
:columns = "productColumns"
@confirm ="onProductConfirm"
/ >
< / view >
< / template >
< script lang = "ts" setup >
import type { FormInstance } from 'wot-design-uni/components/wd-form/types'
import type { PurchaseRequisition , PurchaseRequisitionItem } from '@/api/erp/purchase-requisition'
import type { ProductSimple } from '@/api/erp/product'
import { computed , onMounted , ref } from 'vue'
import { useToast } from 'wot-design-uni'
import {
@@ -233,6 +265,7 @@ import {
REQUISITION _TYPE _OPTIONS ,
updatePurchaseRequisition ,
} from '@/api/erp/purchase-requisition'
import { getProductSimpleList } from '@/api/erp/product'
import { navigateBackPlus } from '@/utils'
const props = defineProps < {
@@ -257,11 +290,10 @@ const formData = ref<PurchaseRequisition>({
emergencyDegree : 1 ,
requestTime : undefined ,
expectedTime : undefined ,
remark : undefined ,
remark : '' ,
items : [ ] ,
} )
const formRules = {
type : [ { required : true , message : '请购类型不能为空' } ] ,
requestTime : [ { required : true , message : '请购时间不能为空' } ] ,
expectedTime : [ { required : true , message : '期望到货时间不能为空' } ] ,
}
@@ -269,35 +301,31 @@ const formRef = ref<FormInstance>()
// 类型选择器
const typePickerVisible = ref ( false )
const typeColumns = computed ( ( ) => [
REQUISITION _TYPE _OPTIONS . map ( v => ( { value : v . value , label : v . label } ) ) ,
] )
const typeColumns = computed ( ( ) =>
REQUISITION _TYPE _OPTIONS . map ( v => ( { label : v . label , value : v . value } ) ) ,
)
// 优先级选择器
const priorityPickerVisible = ref ( false )
const priorityColumns = computed ( ( ) => [
PRIORITY _OPTIONS . map ( v => ( { value : v . value , label : v . label } ) ) ,
] )
const priorityColumns = computed ( ( ) =>
PRIORITY _OPTIONS . map ( v => ( { label : v . label , value : v . value } ) ) ,
)
// 紧急程度选择器
const emergencyPickerVisible = ref ( false )
const emergencyColumns = computed ( ( ) => [
EMERGENCY _OPTIONS . map ( v => ( { value : v . value , label : v . label } ) ) ,
] )
const emergencyColumns = computed ( ( ) =>
EMERGENCY _OPTIONS . map ( v => ( { label : v . label , value : v . value } ) ) ,
)
// 日期选择器
const requestDatePickerVisible = ref ( false )
const expectedDatePickerVisible = ref ( false )
// 产品列表
const productList = ref <{ id : number , name : string , unitName ? : string } [ ] >( [ ] )
const productPickerVisible = ref ( false )
const productColumns = computed ( ( ) => [
productList . value . map ( v => ( { value : v . id , label : v . name } ) ) ,
] )
// 当前编辑的产品项索引
const currentItemIndex = ref ( - 1 )
const productList = ref <ProductSimple [ ] >( [ ] )
const productColumns = computed ( ( ) =>
productList . value . map ( v => ( { label : v . name , value : v . id } ) ) ,
)
/** 合计数量 */
const totalCount = computed ( ( ) => {
@@ -347,14 +375,14 @@ function formatPrice(price?: number) {
}
/** 格式化日期 */
function formatDate ( dateStr ? : string ) {
if ( ! dateStr ) return '-'
if ( typeof dateStr === 'number' ) {
const d = new Date ( dateStr )
function formatDate ( dateVal ? : string | number ) {
if ( ! dateVal ) return '-'
if ( typeof dateVal === 'number' ) {
const d = new Date ( dateVal )
const pad = ( n : number ) => n . toString ( ) . padStart ( 2 , '0' )
return ` ${ d . getFullYear ( ) } - ${ pad ( d . getMonth ( ) + 1 ) } - ${ pad ( d . getDate ( ) ) } `
}
return dateStr . substring ( 0 , 10 )
return String ( dateVal ) . substring ( 0 , 10 )
}
/** 返回上一页 */
@@ -362,6 +390,16 @@ function handleBack() {
navigateBackPlus ( '/pages-erp/purchase-requisition/index' )
}
/** 加载下拉列表数据 */
async function loadDropdownData ( ) {
try {
const products = await getProductSimpleList ( )
productList . value = products || [ ]
} catch {
// error handled by http
}
}
/** 加载详情 */
async function getDetail ( ) {
if ( ! props . id ) return
@@ -375,19 +413,19 @@ async function getDetail() {
/** 类型确认 */
function onTypeConfirm ( { value } : any ) {
formData . value . type = value ? . [ 0 ]
formData . value . type = value ? . [ 0 ] ? ? formData . value . type
typePickerVisible . value = false
}
/** 优先级确认 */
function onPriorityConfirm ( { value } : any ) {
formData . value . priority = value ? . [ 0 ]
formData . value . priority = value ? . [ 0 ] ? ? formData . value . priority
priorityPickerVisible . value = false
}
/** 紧急程度确认 */
function onEmergencyConfirm ( { value } : any ) {
formData . value . emergencyDegree = value ? . [ 0 ]
formData . value . emergencyDegree = value ? . [ 0 ] ? ? formData . value . emergencyDegree
emergencyPickerVisible . value = false
}
@@ -403,47 +441,58 @@ function onExpectedDateConfirm({ value }: any) {
expectedDatePickerVisible . value = false
}
/** 打开 产品选择器 */
function ope nProductPicker ( index : number ) {
currentItemIndex . value = index
productPickerVisible . value = true
}
/** 产品确认 */
function onProductConfirm ( { value } : any ) {
if ( currentItemIndex . valu e > = 0 && formData . value . items ) {
const item = formData . value . items [ currentItemIndex . value ]
item . productId = value ? . [ 0 ]
const product = productList . value . find ( p => p . id === item . productId )
item . productNam e = product ? . name
item . productUnitNam e = product ? . unitNam e
/** 产品选择回调:自动填充规格/单位/条码 */
function onProductConfirm ( { value } : any , index : number ) {
const productId = value ? . [ 0 ]
if ( formData . value . items && formData . value . items [ index ] ) {
const item = formData . value . items [ index ]
item . productId = productId
const product = productList . value . find ( p => p . id === productId )
if ( product ) {
item . productNam e = product . name
item . productSpec = product . standard || ''
item . productUnitName = product . unitName || ''
item . productUnitId = product . unitId as any
item . productBarCod e = product . barCode || ''
item . productPric e = product . purchasePric e
}
}
productPickerVisible . value = false
}
/** 添加产品项 */
function a ddItem( ) {
function handleA ddItem( ) {
if ( ! formData . value . items ) {
formData . value . items = [ ]
}
formData . value . items . push ( {
productId : undefined ,
productName : undefined ,
productUnitName : undefined ,
count : undefined ,
productId : undefined as any ,
productName : undefined as any ,
productUnitId : undefined as any ,
productUnitName : undefined as any ,
productSpec : undefined as any ,
productBarCode : undefined as any ,
productPrice : undefined ,
count : 1 as any ,
totalProductPrice : 0 ,
taxPercent : undefined ,
taxPrice : 0 ,
totalPrice : 0 ,
purpose : undefined ,
remark : undefined ,
purpose : '' ,
remark : '' ,
} )
}
/** 移除产品项 */
function r emoveItem( index : number ) {
function handleR emoveItem( index : number ) {
uni . showModal ( {
title : '提示' ,
content : ` 确定要删除第 ${ index + 1 } 项产品吗? ` ,
success : ( res ) => {
if ( res . confirm ) {
formData . value . items ? . splice ( index , 1 )
}
} ,
} )
}
/** 计算产品项金额(含税) */
@@ -472,13 +521,14 @@ async function handleSubmit() {
return
}
for ( const item of formData . value . items ) {
for ( let i = 0 ; i < formData . value . items . length ; i ++ ) {
const item = formData . value . items [ i ]
if ( ! item . productId ) {
toast . error ( '请选择产品' )
toast . warning ( ` 第 ${ i + 1 } 项产品ID不能为空 ` )
return
}
if ( ! item . count || Number ( item . count ) <= 0 ) {
toast . error ( '请输入有效的数量' )
if ( ! item . count ) {
toast . warning ( ` 第 ${ i + 1 } 项产品数量不能为空 ` )
return
}
}
@@ -508,7 +558,7 @@ async function handleSubmit() {
/** 初始化 */
onMounted ( async ( ) => {
// 加载详情
await loadDropdownData ( )
getDetail ( )
} )
< / script >