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

865 lines
27 KiB
Vue
Raw Normal View History

<template>
<a-modal
:visible="visible"
:title="getModalTitle()"
width="1200px"
:confirm-loading="loading"
:ok-button-props="{ disabled: !isFormValid || isView }"
@cancel="handleCancel"
@ok="handleSubmit"
>
<a-form
ref="formRef"
:model="formData"
:rules="rules"
:label-col="{ span: 6 }"
:wrapper-col="{ span: 16 }"
auto-label-width
>
<!-- 标签页导航 -->
<div class="tab-navigation">
<div
v-for="tab in tabs"
:key="tab.key"
class="tab-item" :class="[{ active: activeTab === tab.key }]"
@click="activeTab = tab.key"
>
{{ tab.label }}
</div>
</div>
<!-- 标签页内容 -->
<div class="tab-content">
<!-- 基本信息 -->
<div v-show="activeTab === 'basic'">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="设备名称" field="equipmentName">
<a-input
v-model="formData.equipmentName"
placeholder="请输入设备名称"
:disabled="isView"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="设备类型" field="equipmentType">
<a-select
v-model="formData.equipmentType"
:options="equipmentTypeOptions"
placeholder="请选择设备类型"
:disabled="isView"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="设备型号" field="equipmentModel">
<a-input
v-model="formData.equipmentModel"
placeholder="请输入设备型号"
:disabled="isView"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="序列号" field="equipmentSn">
<a-input
v-model="formData.equipmentSn"
placeholder="请输入序列号"
:disabled="isView"
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="brand">
<a-input
v-model="formData.brand"
placeholder="请输入品牌"
:disabled="isView"
show-word-limit
:max-length="100"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="资产编号" field="assetCode">
<a-input
v-model="formData.assetCode"
placeholder="请输入资产编号"
:disabled="isView"
show-word-limit
:max-length="50"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="配置规格" field="specification">
<a-textarea
v-model="formData.specification"
placeholder="请输入配置规格参数"
:disabled="isView"
:rows="3"
show-word-limit
:max-length="500"
/>
</a-form-item>
</div>
<!-- 采购信息 -->
<div v-show="activeTab === 'procurement'">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="采购订单" field="purchaseOrder">
<a-input
v-model="formData.purchaseOrder"
placeholder="请输入采购订单号"
:disabled="isView"
show-word-limit
:max-length="100"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="供应商" field="supplierName">
<a-input
v-model="formData.supplierName"
placeholder="请输入供应商名称"
:disabled="isView"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="数量" field="quantity">
<a-input-number
v-model="formData.quantity"
placeholder="请输入数量"
:min="1"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="单价" field="unitPrice">
<a-input-number
v-model="formData.unitPrice"
placeholder="请输入单价"
:precision="2"
:min="0"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="总价" field="totalPrice">
<a-input-number
v-model="formData.totalPrice"
placeholder="请输入总价"
:precision="2"
:min="0"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="采购价格" field="purchasePrice">
<a-input-number
v-model="formData.purchasePrice"
placeholder="请输入采购价格"
:precision="2"
:min="0"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="当前净值" field="currentNetValue">
<a-input-number
v-model="formData.currentNetValue"
placeholder="请输入当前净值"
:precision="2"
:min="0"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="采购时间" field="purchaseTime">
<a-date-picker
v-model="formData.purchaseTime"
placeholder="请选择采购时间"
:disabled="isView"
show-time
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="入库时间" field="inStockTime">
<a-date-picker
v-model="formData.inStockTime"
placeholder="请选择入库时间"
:disabled="isView"
show-time
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="启用时间" field="activationTime">
<a-date-picker
v-model="formData.activationTime"
placeholder="请选择启用时间"
:disabled="isView"
show-time
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="预计报废时间" field="expectedScrapTime">
<a-date-picker
v-model="formData.expectedScrapTime"
placeholder="请选择预计报废时间"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="折旧方法" field="depreciationMethod">
<a-select
v-model="formData.depreciationMethod"
placeholder="请选择折旧方法"
:disabled="isView"
>
<a-option value="straight_line">直线折旧</a-option>
<a-option value="declining_balance">余额递减</a-option>
<a-option value="sum_of_years">年数总和</a-option>
</a-select>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="折旧年限" field="depreciationYears">
<a-input-number
v-model="formData.depreciationYears"
placeholder="请输入折旧年限"
:min="1"
:max="50"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="残值" field="salvageValue">
<a-input-number
v-model="formData.salvageValue"
placeholder="请输入残值"
:precision="2"
:min="0"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="保修截止日期" field="warrantyExpireDate">
<a-date-picker
v-model="formData.warrantyExpireDate"
placeholder="请选择保修截止日期"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- 状态信息 -->
<div v-show="activeTab === 'status'">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="设备状态" field="equipmentStatus">
<a-select
v-model="formData.equipmentStatus"
:options="equipmentStatusOptions"
placeholder="请选择设备状态"
:disabled="isView"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="使用状态" field="useStatus">
<a-select
v-model="formData.useStatus"
:options="useStatusOptions"
placeholder="请选择使用状态"
:disabled="isView"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="位置状态" field="locationStatus">
<a-select
v-model="formData.locationStatus"
:options="locationStatusOptions"
placeholder="请选择位置状态"
:disabled="isView"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="健康状态" field="healthStatus">
<a-select
v-model="formData.healthStatus"
:options="healthStatusOptions"
placeholder="请选择健康状态"
:disabled="isView"
/>
</a-form-item>
</a-col>
</a-row>
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="负责人" field="responsiblePerson">
<a-input
v-model="formData.responsiblePerson"
placeholder="请输入负责人"
:disabled="isView"
show-word-limit
:max-length="100"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="维护人员" field="maintenancePerson">
<a-input
v-model="formData.maintenancePerson"
placeholder="请输入维护人员"
:disabled="isView"
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="physicalLocation">
<a-input
v-model="formData.physicalLocation"
placeholder="请输入物理位置"
:disabled="isView"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="库存条码" field="inventoryBarcode">
<a-input
v-model="formData.inventoryBarcode"
placeholder="请输入库存条码"
:disabled="isView"
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="lastMaintenanceDate">
<a-date-picker
v-model="formData.lastMaintenanceDate"
placeholder="请选择上次维护日期"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="下次维护日期" field="nextMaintenanceDate">
<a-date-picker
v-model="formData.nextMaintenanceDate"
placeholder="请选择下次维护日期"
:disabled="isView"
style="width: 100%"
/>
</a-form-item>
</a-col>
</a-row>
</div>
<!-- 其他信息 -->
<div v-show="activeTab === 'other'">
<a-row :gutter="16">
<a-col :span="12">
<a-form-item label="次户号" field="accountNumber">
<a-input
v-model="formData.accountNumber"
placeholder="请输入次户号"
:disabled="isView"
show-word-limit
:max-length="100"
/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="盘点依据" field="inventoryBasis">
<a-input
v-model="formData.inventoryBasis"
placeholder="请输入盘点依据"
:disabled="isView"
show-word-limit
:max-length="200"
/>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="动态记录" field="dynamicRecord">
<a-textarea
v-model="formData.dynamicRecord"
placeholder="请输入动态记录"
:disabled="isView"
:rows="4"
show-word-limit
:max-length="1000"
/>
</a-form-item>
<a-form-item label="资产备注" field="assetRemark">
<a-textarea
v-model="formData.assetRemark"
placeholder="请输入资产备注"
:disabled="isView"
:rows="3"
show-word-limit
:max-length="500"
/>
</a-form-item>
</div>
</div>
</a-form>
</a-modal>
</template>
<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { FormInstance } from '@arco-design/web-vue'
import { equipmentProcurementApi } from '@/apis/equipment/procurement'
import type { EquipmentResp, EquipmentReq } from '@/apis/equipment/type'
interface Props {
visible: boolean
procurementData?: EquipmentResp | null
mode: 'add' | 'edit' | 'view'
}
interface Emits {
(e: 'update:visible', value: boolean): void
(e: 'success'): void
}
const props = withDefaults(defineProps<Props>(), {
visible: false,
procurementData: null,
mode: 'add',
})
const emit = defineEmits<Emits>()
const formRef = ref<FormInstance>()
const loading = ref(false)
const activeTab = ref('basic')
// 标签页配置
const tabs = [
{ key: 'basic', label: '基本信息' },
{ key: 'procurement', label: '采购信息' },
{ key: 'status', label: '状态信息' },
{ key: 'other', label: '其他信息' },
]
// 表单数据
const formData = reactive<EquipmentReq>({
equipmentName: '',
equipmentModel: '',
equipmentType: '',
equipmentStatus: '',
useStatus: '',
equipmentSn: '',
assetCode: '',
brand: '',
specification: '',
locationStatus: '',
physicalLocation: '',
responsiblePerson: '',
healthStatus: '',
purchaseTime: '',
inStockTime: '',
activationTime: '',
expectedScrapTime: '',
actualScrapTime: '',
purchaseOrder: '',
supplierName: '',
purchasePrice: undefined,
currentNetValue: undefined,
depreciationMethod: '',
depreciationYears: undefined,
salvageValue: undefined,
warrantyExpireDate: '',
lastMaintenanceDate: '',
nextMaintenanceDate: '',
maintenancePerson: '',
inventoryBarcode: '',
assetRemark: '',
accountNumber: '',
quantity: 1,
unitPrice: undefined,
totalPrice: undefined,
inventoryBasis: '',
dynamicRecord: '',
})
// 表单验证规则
const rules = {
equipmentName: [{ required: true, message: '请输入设备名称' }],
equipmentModel: [{ required: true, message: '请输入设备型号' }],
equipmentType: [{ required: true, message: '请选择设备类型' }],
equipmentSn: [{ required: true, message: '请输入设备序列号' }],
equipmentStatus: [{ required: true, message: '请选择设备状态' }],
useStatus: [{ required: true, message: '请选择使用状态' }],
purchaseOrder: [{ required: true, message: '请输入采购订单号' }],
supplierName: [{ required: true, message: '请输入供应商名称' }],
purchasePrice: [{ required: true, message: '请输入采购价格' }],
quantity: [{ required: true, message: '请输入数量' }],
unitPrice: [{ required: true, message: '请输入单价' }],
totalPrice: [{ required: true, message: '请输入总价' }],
}
// 选项配置
const equipmentTypeOptions = [
{ label: '检测设备', value: 'detection' },
{ label: '安防设备', value: 'security' },
{ label: '办公设备', value: 'office' },
{ label: '车辆', value: 'car' },
{ label: '其他设备', value: 'other' },
]
const equipmentStatusOptions = [
{ label: '正常', value: 'normal' },
{ label: '维修中', value: 'repair' },
{ label: '已报废', value: 'scrap' },
{ label: '闲置', value: 'idle' },
{ label: '丢失', value: 'lost' },
]
const useStatusOptions = [
{ label: '空闲中', value: '0' },
{ label: '使用中', value: '1' },
]
const locationStatusOptions = [
{ label: '库存中', value: 'in_stock' },
{ label: '使用中', value: 'in_use' },
{ label: '维修中', value: 'repair' },
{ label: '已报废', value: 'scrapped' },
{ label: '外借中', value: 'on_loan' },
{ label: '丢失', value: 'lost' },
{ label: '闲置', value: 'idle' },
]
const healthStatusOptions = [
{ label: '优秀', value: 'excellent' },
{ label: '良好', value: 'good' },
{ label: '一般', value: 'normal' },
{ label: '较差', value: 'poor' },
{ label: '危险', value: 'critical' },
]
// 计算属性
const isView = computed(() => props.mode === 'view')
const isFormValid = computed(() => {
return formData.equipmentName &&
formData.equipmentModel &&
formData.equipmentType &&
formData.equipmentSn
})
// 获取弹窗标题
const getModalTitle = () => {
const titles = {
add: '新增采购记录',
edit: '编辑采购记录',
view: '查看采购记录',
}
return titles[props.mode]
}
// 监听弹窗显示状态
watch(() => props.visible, (newVal) => {
if (newVal && props.procurementData) {
initFormData()
}
})
// 初始化表单数据
const initFormData = () => {
if (props.procurementData) {
Object.assign(formData, {
equipmentName: props.procurementData.equipmentName || '',
equipmentModel: props.procurementData.equipmentModel || '',
equipmentType: props.procurementData.equipmentType || '',
equipmentStatus: props.procurementData.equipmentStatus || '',
useStatus: props.procurementData.useStatus || '',
equipmentSn: props.procurementData.equipmentSn || '',
assetCode: props.procurementData.assetCode || '',
brand: props.procurementData.brand || '',
specification: props.procurementData.specification || '',
locationStatus: props.procurementData.locationStatus || '',
physicalLocation: props.procurementData.physicalLocation || '',
responsiblePerson: props.procurementData.responsiblePerson || '',
healthStatus: props.procurementData.healthStatus || '',
purchaseTime: props.procurementData.purchaseTime || '',
inStockTime: props.procurementData.inStockTime || '',
activationTime: props.procurementData.activationTime || '',
expectedScrapTime: props.procurementData.expectedScrapTime || '',
actualScrapTime: props.procurementData.actualScrapTime || '',
purchaseOrder: props.procurementData.purchaseOrder || '',
supplierName: props.procurementData.supplierName || '',
purchasePrice: props.procurementData.purchasePrice,
currentNetValue: props.procurementData.currentNetValue,
depreciationMethod: props.procurementData.depreciationMethod || '',
depreciationYears: props.procurementData.depreciationYears,
salvageValue: props.procurementData.salvageValue,
warrantyExpireDate: props.procurementData.warrantyExpireDate || '',
lastMaintenanceDate: props.procurementData.lastMaintenanceDate || '',
nextMaintenanceDate: props.procurementData.nextMaintenanceDate || '',
maintenancePerson: props.procurementData.maintenancePerson || '',
inventoryBarcode: props.procurementData.inventoryBarcode || '',
assetRemark: props.procurementData.assetRemark || '',
accountNumber: props.procurementData.accountNumber || '',
quantity: props.procurementData.quantity || 1,
unitPrice: props.procurementData.unitPrice,
totalPrice: props.procurementData.totalPrice,
inventoryBasis: props.procurementData.inventoryBasis || '',
dynamicRecord: props.procurementData.dynamicRecord || '',
})
} else {
resetForm()
}
}
// 重置表单
const resetForm = () => {
Object.assign(formData, {
equipmentName: '',
equipmentModel: '',
equipmentType: '',
equipmentStatus: '',
useStatus: '',
equipmentSn: '',
assetCode: '',
brand: '',
specification: '',
locationStatus: '',
physicalLocation: '',
responsiblePerson: '',
healthStatus: '',
purchaseTime: '',
inStockTime: '',
activationTime: '',
expectedScrapTime: '',
actualScrapTime: '',
purchaseOrder: '',
supplierName: '',
purchasePrice: undefined,
currentNetValue: undefined,
depreciationMethod: '',
depreciationYears: undefined,
salvageValue: undefined,
warrantyExpireDate: '',
lastMaintenanceDate: '',
nextMaintenanceDate: '',
maintenancePerson: '',
inventoryBarcode: '',
assetRemark: '',
accountNumber: '',
quantity: 1,
unitPrice: undefined,
totalPrice: undefined,
inventoryBasis: '',
dynamicRecord: '',
})
formRef.value?.resetFields()
}
// 提交表单
const handleSubmit = async () => {
try {
await formRef.value?.validate()
loading.value = true
if (props.mode === 'edit' && props.procurementData) {
await equipmentProcurementApi.update(props.procurementData.equipmentId, formData)
Message.success('更新成功')
} else {
await equipmentProcurementApi.add(formData)
Message.success('新增成功')
}
emit('success')
} catch (error: any) {
console.error('操作失败:', error)
Message.error(error?.message || '操作失败')
} finally {
loading.value = false
}
}
// 取消
const handleCancel = () => {
emit('update:visible', false)
resetForm()
}
</script>
<style scoped lang="scss">
.tab-navigation {
display: flex;
border-bottom: 1px solid var(--color-border);
margin-bottom: 24px;
.tab-item {
padding: 12px 24px;
cursor: pointer;
border-bottom: 2px solid transparent;
transition: all 0.3s ease;
font-weight: 500;
color: var(--color-text-2);
&:hover {
color: var(--color-primary);
}
&.active {
color: var(--color-primary);
border-bottom-color: var(--color-primary);
}
}
}
.tab-content {
.arco-form-item {
margin-bottom: 24px;
.arco-form-item-label {
font-weight: 500;
color: var(--color-text-1);
margin-bottom: 8px;
}
}
.arco-input,
.arco-select,
.arco-input-number,
.arco-date-picker {
border-radius: 6px;
border: 1px solid var(--color-border);
transition: all 0.2s ease;
&:hover {
border-color: var(--color-primary-light-3);
}
&:focus,
&.arco-input-focus,
&.arco-select-focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.1);
}
}
.arco-textarea {
border-radius: 6px;
border: 1px solid var(--color-border);
transition: all 0.2s ease;
&:hover {
border-color: var(--color-primary-light-3);
}
&:focus,
&.arco-textarea-focus {
border-color: var(--color-primary);
box-shadow: 0 0 0 2px rgba(var(--primary-6), 0.1);
}
}
}
// 响应式设计
@media (max-width: 768px) {
.tab-navigation {
.tab-item {
padding: 8px 16px;
font-size: 14px;
}
}
.tab-content {
.arco-row {
.arco-col {
margin-bottom: 16px;
}
}
}
}
</style>