Industrial-image-management.../src/views/system-resource/device-management/procurement/components/ReceiptModal.vue

510 lines
16 KiB
Vue

<template>
<a-modal
:visible="visible"
title="确认收货"
width="800px"
:confirm-loading="loading"
@cancel="handleCancel"
@ok="handleSubmit"
>
<a-form
ref="formRef"
:model="formData"
:rules="rules"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 18 }"
layout="vertical"
>
<!-- 基本信息 -->
<a-card title="设备信息" class="detail-card" :bordered="false">
<a-descriptions :column="2" bordered>
<a-descriptions-item label="设备名称">
{{ equipmentData?.equipmentName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="设备类型">
{{ equipmentData?.equipmentType || '-' }}
</a-descriptions-item>
<a-descriptions-item label="设备型号">
{{ equipmentData?.equipmentModel || '-' }}
</a-descriptions-item>
<a-descriptions-item label="品牌">
{{ equipmentData?.brand || '-' }}
</a-descriptions-item>
<a-descriptions-item label="供应商">
{{ equipmentData?.supplierName || '-' }}
</a-descriptions-item>
<a-descriptions-item label="采购订单">
{{ equipmentData?.purchaseOrder || '-' }}
</a-descriptions-item>
</a-descriptions>
</a-card>
<!-- 收货信息 -->
<a-card title="收货信息" class="detail-card" :bordered="false">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="收货时间" field="receiptTime" required>
<a-date-picker
v-model="formData.receiptTime"
show-time
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择收货时间"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="收货人" field="receiptPerson" required>
<a-input
v-model="formData.receiptPerson"
placeholder="请输入收货人姓名"
show-word-limit
:max-length="50"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="收货数量" field="receiptQuantity" required>
<a-input-number
v-model="formData.receiptQuantity"
placeholder="请输入收货数量"
:min="1"
:max="9999"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="入库位置" field="storageLocation" required>
<a-input
v-model="formData.storageLocation"
placeholder="请输入入库位置"
show-word-limit
:max-length="100"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="库管员" field="storageManager" required>
<a-input
v-model="formData.storageManager"
placeholder="请输入库管员姓名"
show-word-limit
:max-length="50"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="收货备注" field="receiptRemark">
<a-input
v-model="formData.receiptRemark"
placeholder="请输入收货备注"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
<!-- 质量检查 -->
<a-card title="质量检查" class="detail-card" :bordered="false">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="外观检查" field="appearanceCheck" required>
<a-select
v-model="formData.appearanceCheck"
placeholder="请选择外观检查结果"
style="width: 100%"
>
<a-option value="正常">正常</a-option>
<a-option value="轻微划痕">轻微划痕</a-option>
<a-option value="明显划痕">明显划痕</a-option>
<a-option value="变形">变形</a-option>
<a-option value="其他">其他</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="功能测试" field="functionTest" required>
<a-select
v-model="formData.functionTest"
placeholder="请选择功能测试结果"
style="width: 100%"
>
<a-option value="正常">正常</a-option>
<a-option value="部分正常">部分正常</a-option>
<a-option value="异常">异常</a-option>
<a-option value="未测试">未测试</a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="包装完整性" field="packageIntegrity" required>
<a-select
v-model="formData.packageIntegrity"
placeholder="请选择包装完整性"
style="width: 100%"
>
<a-option value="完整">完整</a-option>
<a-option value="轻微破损">轻微破损</a-option>
<a-option value="明显破损">明显破损</a-option>
<a-option value="严重破损">严重破损</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="配件完整性" field="accessoryIntegrity" required>
<a-select
v-model="formData.accessoryIntegrity"
placeholder="请选择配件完整性"
style="width: 100%"
>
<a-option value="完整">完整</a-option>
<a-option value="部分缺失">部分缺失</a-option>
<a-option value="严重缺失">严重缺失</a-option>
<a-option value="无配件">无配件</a-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="检查结果" field="checkResult" required>
<a-select
v-model="formData.checkResult"
placeholder="请选择检查结果"
style="width: 100%"
>
<a-option value="PASS">通过</a-option>
<a-option value="FAIL">不通过</a-option>
<a-option value="CONDITIONAL">有条件通过</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="检查备注" field="checkRemark">
<a-input
v-model="formData.checkRemark"
placeholder="请输入检查备注"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
</a-row>
</a-card>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { FormInstance } from '@arco-design/web-vue'
import type { EquipmentResp, ReceiptRequest } from '@/apis/equipment/type'
import { equipmentProcurementApi } from '@/apis/equipment/procurement'
interface Props {
visible: boolean
equipmentData?: EquipmentResp | null
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
equipmentData: null,
})
const emit = defineEmits<{
'update:visible': [value: boolean]
'success': []
}>()
const formRef = ref<FormInstance>()
const loading = ref(false)
// 表单数据 - 使用正确的字段映射
const formData = reactive<ReceiptRequest>({
// 收货特有信息
receiptTime: '',
receiptPerson: '',
receiptQuantity: 1,
receiptRemark: '',
appearanceCheck: '',
functionTest: '',
packageIntegrity: '',
accessoryIntegrity: '',
checkResult: 'PASS',
checkRemark: '',
storageLocation: '',
storageManager: '',
// 设备基本信息(从采购数据继承)
equipmentName: '',
equipmentModel: '',
equipmentType: '',
equipmentSn: '',
brand: '',
specification: '',
assetCode: '',
// 采购信息(从采购数据继承)
purchaseOrder: '',
supplierName: '',
purchasePrice: 0,
purchaseTime: '',
quantity: 1,
unitPrice: 0,
totalPrice: 0,
// 入库信息
inStockTime: '',
physicalLocation: '',
locationStatus: '',
responsiblePerson: '',
inventoryBarcode: '',
// 状态信息
equipmentStatus: '',
useStatus: '',
healthStatus: '',
receiptStatus: '',
// 其他管理信息
depreciationMethod: '',
depreciationYears: 5,
salvageValue: 0,
currentNetValue: 0,
// 系统字段
createTime: '',
updateTime: ''
})
// 表单验证规则
const rules = {
receiptTime: [
{ required: true, message: '请选择收货时间' }
],
receiptPerson: [
{ required: true, message: '请输入收货人姓名' },
{ min: 2, max: 50, message: '收货人姓名长度应在2-50个字符之间' }
],
receiptQuantity: [
{ required: true, message: '请输入收货数量' },
{ type: 'number', min: 1, max: 9999, message: '收货数量应在1-9999之间' }
],
storageLocation: [
{ required: true, message: '请输入入库位置' },
{ min: 2, max: 100, message: '入库位置长度应在2-100个字符之间' }
],
storageManager: [
{ required: true, message: '请输入库管员姓名' },
{ min: 2, max: 50, message: '库管员姓名长度应在2-50个字符之间' }
],
appearanceCheck: [
{ required: true, message: '请选择外观检查结果' }
],
functionTest: [
{ required: true, message: '请选择功能测试结果' }
],
packageIntegrity: [
{ required: true, message: '请选择包装完整性' }
],
accessoryIntegrity: [
{ required: true, message: '请选择配件完整性' }
],
checkResult: [
{ required: true, message: '请选择检查结果' }
],
}
// 初始化表单数据
const initFormData = () => {
if (props.equipmentData) {
// 从设备数据中复制相关字段
Object.keys(formData).forEach((key) => {
const formKey = key as keyof ReceiptRequest
const equipmentKey = key as keyof EquipmentResp
if (formKey in formData && equipmentKey in props.equipmentData!) {
const value = props.equipmentData![equipmentKey]
if (value !== undefined) {
(formData[formKey] as any) = value
}
}
})
// 设置默认值
formData.receiptQuantity = props.equipmentData.quantity || 1
formData.storageLocation = props.equipmentData.physicalLocation || ''
formData.storageManager = props.equipmentData.responsiblePerson || ''
// 设置收货时间默认为当前时间
formData.receiptTime = formatDateTime(new Date())
}
}
// 监听弹窗显示状态
watch(() => props.visible, (visible) => {
if (visible) {
initFormData()
formRef.value?.clearValidate()
}
})
// 监听设备数据变化
watch(() => props.equipmentData, () => {
if (props.visible && props.equipmentData) {
initFormData()
}
}, { deep: true })
// 提交表单
const handleSubmit = async () => {
try {
await formRef.value?.validate()
loading.value = true
if (!props.equipmentData?.equipmentId) {
throw new Error('设备ID不能为空')
}
console.log('📦 开始提交收货数据...')
console.log('📦 设备数据:', props.equipmentData)
console.log('📦 表单数据:', formData)
// 构建收货请求数据
const receiptData: ReceiptRequest = {
// 收货特有信息
receiptTime: formData.receiptTime ? formatDateTime(formData.receiptTime) : formatDateTime(new Date()),
receiptPerson: formData.receiptPerson,
receiptQuantity: formData.receiptQuantity,
receiptRemark: formData.receiptRemark,
appearanceCheck: formData.appearanceCheck,
functionTest: formData.functionTest,
packageIntegrity: formData.packageIntegrity,
accessoryIntegrity: formData.accessoryIntegrity,
checkResult: formData.checkResult,
checkRemark: formData.checkRemark,
storageLocation: formData.storageLocation,
storageManager: formData.storageManager,
// 设备基本信息(从采购数据继承)
equipmentName: props.equipmentData.equipmentName,
equipmentModel: props.equipmentData.equipmentModel,
equipmentType: props.equipmentData.equipmentType,
equipmentSn: props.equipmentData.equipmentSn,
brand: props.equipmentData.brand,
specification: props.equipmentData.specification,
assetCode: props.equipmentData.assetCode,
// 采购信息(从采购数据继承)
purchaseOrder: props.equipmentData.purchaseOrder,
supplierName: props.equipmentData.supplierName,
purchasePrice: props.equipmentData.purchasePrice,
purchaseTime: props.equipmentData.purchaseTime,
quantity: props.equipmentData.quantity,
unitPrice: props.equipmentData.unitPrice,
totalPrice: props.equipmentData.totalPrice,
// 入库信息
inStockTime: formData.receiptTime ? formatDateTime(formData.receiptTime) : formatDateTime(new Date()),
physicalLocation: formData.storageLocation,
locationStatus: 'in_stock',
responsiblePerson: formData.storageManager,
inventoryBarcode: props.equipmentData.inventoryBarcode || generateInventoryBarcode(),
// 状态信息
equipmentStatus: 'normal',
useStatus: '0',
healthStatus: 'good',
receiptStatus: 'RECEIVED',
// 其他管理信息
depreciationMethod: props.equipmentData.depreciationMethod || 'straight_line',
depreciationYears: props.equipmentData.depreciationYears || 5,
salvageValue: props.equipmentData.salvageValue || 0,
currentNetValue: props.equipmentData.purchasePrice || 0,
// 系统字段
createTime: formatDateTime(new Date()),
updateTime: formatDateTime(new Date())
}
console.log('📦 构建的收货数据:', receiptData)
// 调用收货API
await equipmentProcurementApi.receiveGoods(
props.equipmentData.equipmentId,
receiptData
)
Message.success('收货成功,设备已自动入库')
emit('success')
emit('update:visible', false)
} catch (error: any) {
console.error('收货失败:', error)
Message.error(error?.message || '收货失败,请检查表单信息')
} finally {
loading.value = false
}
}
// 生成库存条码的辅助函数
const generateInventoryBarcode = () => {
const timestamp = Date.now().toString(36)
const random = Math.random().toString(36).substr(2, 5)
return `INV-${timestamp}-${random}`.toUpperCase()
}
// 格式化日期时间
const formatDateTime = (date: string | Date) => {
const d = new Date(date);
let month = '' + (d.getMonth() + 1);
let day = '' + d.getDate();
const year = d.getFullYear();
if (month.length < 2)
month = '0' + month;
if (day.length < 2)
day = '0' + day;
return [year, month, day].join('-') + ' ' + [d.getHours(), d.getMinutes(), d.getSeconds()].join(':');
}
// 取消
const handleCancel = () => {
emit('update:visible', false)
}
</script>
<style scoped lang="scss">
.detail-card {
margin-bottom: 16px;
&:last-child {
margin-bottom: 0;
}
}
.arco-form-item {
margin-bottom: 16px;
}
.arco-input,
.arco-select,
.arco-input-number,
.arco-date-picker {
border-radius: 6px;
}
</style>