优化设备采购界面搜索

This commit is contained in:
Mr.j 2025-08-05 21:41:13 +08:00
parent 749b24a17f
commit 60deb39de8
7 changed files with 2294 additions and 1946 deletions

View File

@ -2,6 +2,10 @@
*
*/
export interface EquipmentListReq {
/** 最低价格 */
minPrice?: number
/** 最高价格 */
maxPrice?: number
/** 设备名称 */
equipmentName?: string
/** 设备类型 */
@ -74,6 +78,8 @@ export interface EquipmentListReq {
orderDirection?: string
/** 页码 */
page?: number
/** 库存条码 */
inventoryBarcode?: string
}
/**

View File

@ -83,7 +83,7 @@ const storeSetup = () => {
// 合并路由
const setRoutes = (data: RouteRecordRaw[]) => {
// 合并路由并排序
routes.value = [...constantRoutes, ...systemRoutes].concat(data)
routes.value = [...constantRoutes, ...systemRoutes, ...data]
.sort((a, b) => (a.meta?.sort ?? 0) - (b.meta?.sort ?? 0))
asyncRoutes.value = data
}
@ -181,8 +181,8 @@ const storeSetup = () => {
}]
// 使用已转换的数据生成路由
const asyncRoutes = formatAsyncRoutes(data as unknown as RouteItem[])
// 合并systemRoutes中的路由
const allRoutes = [...asyncRoutes, ...systemRoutes]
// 合并路由,避免重复
const allRoutes = [...asyncRoutes]
const flatRoutes = flatMultiLevelRoutes(cloneDeep(allRoutes))
setRoutes(allRoutes)
return flatRoutes

View File

@ -0,0 +1,210 @@
# 设备采购模块
## 功能概述
设备采购模块是一个完整的企业设备采购管理系统,提供设备采购的全生命周期管理,包括采购申请、订单管理、供应商管理、设备入库等功能。
## 主要功能
### 1. 采购记录管理
- **新增采购记录**:支持完整的设备采购信息录入
- **编辑采购记录**:修改已存在的采购记录信息
- **查看采购记录**:查看采购记录的详细信息
- **删除采购记录**:删除不需要的采购记录
### 2. 搜索功能
- **多条件搜索**:支持按设备名称、型号、供应商、状态等条件搜索
- **时间范围搜索**:支持按采购时间、入库时间、启用时间范围搜索
- **价格范围搜索**:支持按价格范围搜索
- **状态搜索**:支持按设备状态、位置状态、健康状态搜索
### 3. 数据展示
- **统计卡片**:显示采购总数、待处理、已完成、采购总额等统计信息
- **表格展示**:分页展示采购记录列表
- **状态标签**:使用不同颜色的标签显示设备状态
- **价格格式化**:自动格式化价格显示
### 4. 数据导出
- **Excel导出**支持将采购记录导出为Excel文件
- **筛选导出**:支持按搜索条件导出数据
## 技术架构
### 前端技术栈
- **Vue 3**使用Composition API
- **TypeScript**:提供类型安全
- **Arco Design Vue**UI组件库
- **Vite**:构建工具
### 后端技术栈
- **Spring Boot**:后端框架
- **MyBatis Plus**ORM框架
- **MySQL**:数据库
- **Swagger**API文档
### 数据模型
- **EquipmentEntity**:设备实体类
- **EquipmentReq**:设备请求类
- **EquipmentResp**:设备响应类
- **EquipmentListReq**:设备列表查询请求类
## 文件结构
```
procurement/
├── index.vue # 主页面
├── components/
│ ├── ProcurementSearch.vue # 搜索组件
│ └── ProcurementModal.vue # 弹窗组件
├── test.vue # 测试页面
└── README.md # 说明文档
```
## API接口
### 1. 分页查询
- **接口**`GET /equipment/procurement/page`
- **参数**EquipmentListReq
- **返回**PageResult<EquipmentResp>
### 2. 新增采购
- **接口**`POST /equipment/procurement`
- **参数**EquipmentReq
- **返回**Result<null>
### 3. 更新采购
- **接口**`PUT /equipment/procurement/{equipmentId}`
- **参数**EquipmentReq
- **返回**Result<null>
### 4. 删除采购
- **接口**`DELETE /equipment/procurement/{equipmentId}`
- **参数**equipmentId
- **返回**Result<null>
### 5. 获取详情
- **接口**`GET /equipment/procurement/detail/{equipmentId}`
- **参数**equipmentId
- **返回**Result<EquipmentResp>
### 6. 导出数据
- **接口**`GET /equipment/procurement/export`
- **参数**EquipmentListReq
- **返回**Blob
## 使用说明
### 1. 访问页面
在浏览器中访问设备采购模块页面。
### 2. 查看数据
页面会自动加载采购记录列表,显示统计信息和数据表格。
### 3. 搜索数据
点击"搜索采购"按钮,在弹出的搜索弹窗中输入搜索条件,点击"搜索"按钮。
### 4. 新增记录
点击"新增采购"按钮,在弹出的表单中填写设备采购信息,点击"确定"按钮。
### 5. 编辑记录
在表格中点击"编辑"按钮,在弹出的表单中修改信息,点击"确定"按钮。
### 6. 删除记录
在表格中点击"删除"按钮,确认删除操作。
### 7. 导出数据
点击"导出"按钮选择保存位置下载Excel文件。
## 字段说明
### 基本信息
- **设备名称**:设备的名称
- **设备类型**:设备的分类(检测设备、安防设备、办公设备、车辆等)
- **设备型号**:设备的具体型号
- **序列号**:设备的唯一序列号
- **品牌**:设备的品牌
- **资产编号**:设备的资产编号
- **配置规格**:设备的配置规格和参数
### 采购信息
- **采购订单**:采购订单号
- **供应商**:供应商名称
- **数量**:采购数量
- **单价**:设备单价
- **总价**:设备总价
- **采购价格**:采购价格
- **当前净值**:设备的当前净值
- **采购时间**:采购时间
- **入库时间**:入库时间
- **启用时间**:启用时间
- **预计报废时间**:预计报废时间
- **折旧方法**:折旧方法(直线折旧、余额递减、年数总和)
- **折旧年限**:折旧年限
- **残值**:设备残值
- **保修截止日期**:保修截止日期
### 状态信息
- **设备状态**:设备状态(正常、维修中、已报废、闲置、丢失)
- **使用状态**:使用状态(空闲中、使用中)
- **位置状态**:位置状态(库存中、使用中、维修中、已报废、外借中、丢失、闲置)
- **健康状态**:健康状态(优秀、良好、一般、较差、危险)
- **负责人**:设备负责人
- **维护人员**:维护人员
- **物理位置**:设备的物理位置
- **库存条码**:库存条码
- **上次维护日期**:上次维护日期
- **下次维护日期**:下次维护日期
### 其他信息
- **次户号**:次户号
- **盘点依据**:盘点依据
- **动态记录**:动态记录信息
- **资产备注**:资产备注信息
## 注意事项
1. **数据验证**:所有必填字段都需要填写,系统会进行数据验证
2. **权限控制**:不同用户可能有不同的操作权限
3. **数据安全**:敏感数据会进行加密处理
4. **性能优化**:大量数据时会进行分页处理
5. **错误处理**:系统会显示友好的错误提示
## 开发说明
### 1. 开发环境
- Node.js 16+
- Vue 3.3+
- TypeScript 5.0+
### 2. 安装依赖
```bash
npm install
```
### 3. 启动开发服务器
```bash
npm run dev
```
### 4. 构建生产版本
```bash
npm run build
```
### 5. 代码规范
- 使用ESLint进行代码检查
- 使用Prettier进行代码格式化
- 遵循Vue 3 Composition API最佳实践
## 更新日志
### v1.0.0 (2025-01-XX)
- 初始版本发布
- 实现基本的CRUD功能
- 实现搜索和导出功能
- 实现统计信息展示
- 实现响应式设计
## 联系方式
如有问题或建议,请联系开发团队。

View File

@ -0,0 +1,865 @@
<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>

View File

@ -0,0 +1,136 @@
<template>
<div class="procurement-test">
<a-card title="设备采购模块测试" :bordered="false">
<template #extra>
<a-space>
<a-button type="primary" @click="testApi">
测试API
</a-button>
<a-button @click="testSearch">
测试搜索
</a-button>
<a-button @click="testAdd">
测试新增
</a-button>
</a-space>
</template>
<a-divider />
<div class="test-results">
<h3>测试结果</h3>
<a-textarea
v-model="testResults"
:rows="10"
placeholder="测试结果将显示在这里..."
readonly
/>
</div>
<a-divider />
<div class="test-params">
<h3>测试参数</h3>
<a-form layout="vertical">
<a-row :gutter="16">
<a-col :span="8">
<a-form-item label="设备名称">
<a-input v-model="testParams.equipmentName" placeholder="测试设备" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="设备型号">
<a-input v-model="testParams.equipmentModel" placeholder="测试型号" />
</a-form-item>
</a-col>
<a-col :span="8">
<a-form-item label="供应商">
<a-input v-model="testParams.supplierName" placeholder="测试供应商" />
</a-form-item>
</a-col>
</a-row>
</a-form>
</div>
</a-card>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { Message } from '@arco-design/web-vue'
import { equipmentProcurementApi } from '@/apis/equipment/procurement'
defineOptions({ name: 'ProcurementTest' })
const testResults = ref('')
const testParams = reactive({
equipmentName: '测试设备',
equipmentModel: '测试型号',
supplierName: '测试供应商',
})
//
const addTestResult = (message: string) => {
const timestamp = new Date().toLocaleString()
testResults.value += `[${timestamp}] ${message}\n`
}
// API
const testApi = async () => {
try {
addTestResult('开始测试API...')
const params = {
page: 1,
pageSize: 10,
equipmentName: testParams.equipmentName,
equipmentModel: testParams.equipmentModel,
supplierName: testParams.supplierName,
}
addTestResult(`请求参数: ${JSON.stringify(params, null, 2)}`)
const response = await equipmentProcurementApi.page(params)
addTestResult(`API响应: ${JSON.stringify(response, null, 2)}`)
Message.success('API测试成功')
} catch (error: any) {
addTestResult(`API测试失败: ${error.message}`)
Message.error('API测试失败')
}
}
//
const testSearch = () => {
addTestResult('测试搜索功能...')
addTestResult(`搜索参数: ${JSON.stringify(testParams, null, 2)}`)
Message.info('搜索测试完成')
}
//
const testAdd = () => {
addTestResult('测试新增功能...')
addTestResult(`新增参数: ${JSON.stringify(testParams, null, 2)}`)
Message.info('新增测试完成')
}
</script>
<style scoped lang="scss">
.procurement-test {
.test-results {
margin-bottom: 24px;
h3 {
margin-bottom: 16px;
color: var(--color-text-1);
}
}
.test-params {
h3 {
margin-bottom: 16px;
color: var(--color-text-1);
}
}
}
</style>