bonus-ui/src/views/EquipmentRetireApply/components/AddItemDialog.vue

526 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<el-dialog
v-if="visible"
title="添加装备/工具"
:visible.sync="visible"
width="1400px"
@close="onClose"
>
<!-- 搜索条件 -->
<el-form ref="queryForm" label-width="40px" inline :model="queryParams">
<el-form-item label="名称" prop="typeName">
<el-input v-model="queryParams.typeName" placeholder="请输入名称" clearable style="width: 202px"/>
</el-form-item>
<el-form-item label="规格型号" prop="typeModelName" label-width="70px">
<el-input v-model="queryParams.typeModelName" maxlength="20" placeholder="请输入规格型号" clearable style="width: 202px"/>
</el-form-item>
<el-form-item label="设备编码" prop="devCode" label-width="70px">
<el-input v-model="queryParams.devCode" maxlength="20" placeholder="请输入编码" clearable style="width: 202px"/>
</el-form-item>
<el-form-item label="分类" prop="devType" label-width="40px">
<el-select v-model="queryParams.devType" placeholder="请选择分类" clearable style="width: 202px">
<el-option label="装备" value="1" />
<el-option label="工具" value="2" />
</el-select>
</el-form-item>
<!-- 新增:动态显示的管理模式下拉框 -->
<el-form-item
v-if="queryParams.devType === '2'"
label="管理模式"
label-width="70px"
prop="manageType"
>
<el-select
v-model="queryParams.manageType"
placeholder="请选择管理模式"
clearable
style="width: 202px"
>
<el-option label="编码设备" value="0"/>
<el-option label="数量设备" value="1"/>
</el-select>
</el-form-item>
<!-- &lt;!&ndash; 新增:装备分类下拉框 &ndash;&gt;-->
<!-- <el-col :span="5">-->
<!-- <el-form-item label="装备类目" prop="equipmentCategory">-->
<!-- <el-cascader-->
<!-- v-model="queryParams.equipmentCategory"-->
<!-- :options="equipmentTreeData"-->
<!-- :props="equipmentCascaderProps"-->
<!-- placeholder="请选择装备类目"-->
<!-- clearable-->
<!-- filterable-->
<!-- popper-class="six-level-cascader"-->
<!-- @change="handleEquipmentCategoryChange"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<!-- &lt;!&ndash; 新增:工具分类下拉框 &ndash;&gt;-->
<!-- <el-col :span="5">-->
<!-- <el-form-item label="工具类目" prop="toolCategory">-->
<!-- <el-cascader-->
<!-- v-model="queryParams.toolCategory"-->
<!-- :options="toolTreeData"-->
<!-- :props="toolCascaderProps"-->
<!-- placeholder="请选择工具类目"-->
<!-- clearable-->
<!-- filterable-->
<!-- popper-class="six-level-cascader"-->
<!-- @change="handleToolCategoryChange"-->
<!-- />-->
<!-- </el-form-item>-->
<!-- </el-col>-->
<el-form-item style="float: right">
<el-button type="primary" size="small" @click="onHandleQuery">查询</el-button>
<el-button size="small" @click="onHandleReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 在修装备/工具列表 -->
<el-table
ref="itemTable"
:data="itemList"
row-key="id"
style="width: 100%"
border
stripe
size="small"
fit
height="546"
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="50" :selectable="selectable" :reserve-selection="true"/>
<el-table-column align="center" type="index" label="序号" width="100" />
<el-table-column align="center" prop="devType" label="分类" min-width="70" >
<template slot-scope="scope">
<span v-if="scope.row.devType==1">{{ '装备' }}</span>
<span v-if="scope.row.devType==2">{{ '工具' }}</span>
</template>
</el-table-column>
<el-table-column align="center" prop="groupName" label="类目" min-width="80" />
<el-table-column align="center" prop="typeName" label="名称" min-width="80" />
<el-table-column align="center" prop="typeModelName" label="规格型号" min-width="100" />
<el-table-column align="center" prop="manageMode" label="管理模式" min-width="80" />
<el-table-column align="center" prop="devCode" label="设备编码" min-width="100" />
<el-table-column align="center" prop="inStockNum" label="在库数量" width="100" />
<el-table-column align="center" prop="status" label="预警情况" width="120" >
<template slot-scope="scope">
<span :class="scope.row.status.includes('告警')?'red':''">{{ scope.row.status }}
</span>
</template>
</el-table-column>
<el-table-column align="center" prop="scrapQuantity" label="申请退役数量" width="150">
<template slot-scope="scope">
<el-input-number
v-model="scope.row.scrapQuantity"
:min="1"
:max="scope.row.inStockNum"
size="small"
style="width: 100%"
/>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<div style="text-align: right; margin-top: 15px;">
<el-pagination
:current-page.sync="queryParams.pageNum"
:page-size.sync="queryParams.pageSize"
:page-sizes="[10, 20, 50]"
:total="total"
layout="total, sizes, prev, pager, next, jumper"
/>
</div>
<!-- 操作按钮 -->
<span slot="footer" class="dialog-footer">
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="openConfirm">确定</el-button>
</span>
</el-dialog>
<ConfirmationDialog ref="confirmationDlg" @confirm="onHandleConfirm" />
</div>
</template>
<script>
import { getScrapItemListAPI } from '@/api/EquipmentRetireApply/index.js'
// 导入分类树接口(与之前项目保持一致)
import { getEquipmentTreeAPI } from '@/api/EquipmentConfig/index.js'
import { getTreeSelectApi } from '@/api/toolsManage/index.js'
import ConfirmationDialog from '@/views/business/components/ConfirmationDialog'
export default {
props: {
existingItems: {
type: Array,
default: () => []
}
},
components: { ConfirmationDialog },
data() {
return {
visible: false,
queryParams: {
name: '',
typeName:'',
devType: '',
manageType: '',
typeModelName: '',
devCode: '',
equipmentCategory: [], // 新增:装备分类路径(数组)
toolCategory: [], // 新增:工具分类路径(数组)
equipmentCategoryId: '', // 新增装备分类ID用于接口查询
toolCategoryId: '', // 新增工具分类ID用于接口查询
pageNum: 1,
pageSize: 10
},
itemList: [],
total: 0,
selectedItems: [],
allSelectedItems: [], // 保存所有页面的选中项
// // 新增:分类树相关数据
// equipmentTreeData: [], // 装备分类树
// toolTreeData: [], // 工具分类树
//
// // 装备分类级联配置
// equipmentCascaderProps: {
// value: 'id',
// label: 'name',
// children: 'children',
// checkStrictly: true,
// expandTrigger: 'click'
// },
//
// // 工具分类级联配置匹配返回字段typeId/typeName
// toolCascaderProps: {
// value: 'typeId',
// label: 'typeName',
// children: 'children',
// checkStrictly: true,
// expandTrigger: 'click'
// }
}
},
watch: {
'queryParams.pageNum'() {
this.getItemList()
},
'queryParams.pageSize'() {
this.queryParams.pageNum = 1
this.getItemList()
},
// 分类切换时清空对应类目选择
'queryParams.devType'(val) {
if (val === '装备') {
this.queryParams.toolCategory = []
this.queryParams.toolCategoryId = ''
} else if (val === '工具') {
this.queryParams.equipmentCategory = []
this.queryParams.equipmentCategoryId = ''
}
}
},
created() {
// 初始化加载分类树数据
this.getEquipmentTree()
this.getToolTree()
},
methods: {
open() {
this.visible = true;
// 1. 清空选中项数组(关键)
this.selectedItems = [];
this.allSelectedItems = [];
// 2. 强制清空表格DOM层面的选中状态解决reserve-selection残留
if (this.$refs.itemTable) {
this.$refs.itemTable.clearSelection();
}
// 3. 重置页码并重新获取列表(确保每次打开都是第一页)
this.queryParams.pageNum = 1;
this.getItemList();
// 4. 强制更新表格重新计算selectable状态
this.$nextTick(() => {
if (this.$refs.itemTable) this.$refs.itemTable.$forceUpdate();
});
},
async getItemList() {
try {
// 构造查询参数传递分类ID
const query = {
...this.queryParams,
// 只传递最终的分类ID简化接口参数
equipmentCategory: this.queryParams.equipmentCategoryId,
toolCategory: this.queryParams.toolCategoryId,
manageType: this.queryParams.manageType,
// 新增:将规格型号和设备编码加入查询参数
typeModelName: this.queryParams.typeModelName,
devCode: this.queryParams.devCode,
typeName: this.queryParams.typeName,
}
const res = await getScrapItemListAPI(query)
this.itemList = (res.rows || []).map(item => ({
...item,
scrapQuantity: item.scrapQuantity || 1
}))
this.total = res.total || 0
} catch (error) {
this.$message.error('获取列表失败')
}
},
onHandleQuery() {
this.queryParams.pageNum = 1
this.getItemList()
},
onHandleReset() {
this.queryParams = {
name: '',
typeName: '',
devType: '',
manageType: '',
equipmentCategory: [],
toolCategory: [],
equipmentCategoryId: '',
toolCategoryId: '',
pageNum: 1,
pageSize: 10
}
this.selectedItems=[]
this.getItemList()
},
selectable(row) {
return !this.existingItems.some(item => item.id === row.id)
},
onSelectionChange(selection) {
this.selectedItems = selection
// 更新所有选中项:移除当前页未选中的,添加当前页新选中的
const currentPageKeyIds = this.itemList.map(item => item.keyId)
// 保留其他页面的选中项
this.allSelectedItems = this.allSelectedItems.filter(item => !currentPageKeyIds.includes(item.keyId))
// 添加当前页的选中项
this.allSelectedItems.push(...selection)
},
openConfirm() {
if (this.selectedItems.length === 0) {
this.$message.warning('请选择至少一项')
return
}
const invalidItems = this.selectedItems.filter(item => !item.scrapQuantity || item.scrapQuantity < 1)
if (invalidItems.length > 0) {
const invalidNames = invalidItems.map(item => item.typeModelName).join('、')
this.$message.warning(`以下项目的申请报废数量必须大于0${invalidNames}`)
return
}
this.$refs.confirmationDlg.openDialog(this.selectedItems)
},
onHandleConfirm() {
// 检查申请报废数量是否有效
// const invalidItems = this.allSelectedItems.filter(item => !item.scrapQuantity || item.scrapQuantity < 1)
// 检查是否有重复的keyId
// const existingKeyIds = this.existingItems.map(item => item.keyId)
// const duplicates = this.allSelectedItems.filter(item => existingKeyIds.includes(item.keyId))
// if (duplicates.length > 0) {
// const duplicateNames = duplicates.map(item => item.typeModelName).join('、')
// this.$message.warning(`以下项目已存在,不能重复添加:${duplicateNames}`)
// return
// }
this.$emit('confirm', this.selectedItems)
this.visible = false
this.selectedItems = []
this.allSelectedItems = []
},
onClose() {
this.selectedItems = []
this.allSelectedItems = []
// 1. 重置查询参数(复用重置方法)
this.onHandleReset()
// 2. 清空弹窗显示状态
this.visible = false
},
// 新增:装备分类选择变化
handleEquipmentCategoryChange(value) {
if (value && value.length > 0) {
// 取最后一级分类ID
this.queryParams.equipmentCategoryId = String(value[value.length - 1])
} else {
this.queryParams.equipmentCategoryId = ''
}
},
// 新增:工具分类选择变化
handleToolCategoryChange(value) {
if (value && value.length > 0) {
// 取最后一级分类ID
this.queryParams.toolCategoryId = String(value[value.length - 1])
} else {
this.queryParams.toolCategoryId = ''
}
},
// 新增:处理分类树数据(适配六级分类)
processTreeData(data) {
return Array.isArray(data) ? data : data ? [data] : []
},
// 新增:递归处理装备分类节点(限制六级)
processEquipmentTree(data, currentLevel = 1) {
if (currentLevel > 6) return []
return data.map(item => {
const nodeId = item.typeId ? Number(item.typeId) : item.id ? Number(item.id) : ''
const processedItem = {
id: nodeId,
name: item.typeName || item.name,
level: currentLevel,
parentId: item.parentId ? Number(item.parentId) : null,
...item
}
if (item.children && item.children.length > 0 && currentLevel < 6) {
processedItem.children = this.processEquipmentTree(item.children, currentLevel + 1)
} else {
delete processedItem.children
}
return processedItem
})
},
// 新增:获取装备分类树数据
async getEquipmentTree() {
try {
const res = await getEquipmentTreeAPI()
if (res.code === 200) {
const rawTreeData = this.processTreeData(res.data)
this.equipmentTreeData = this.processEquipmentTree(rawTreeData)
} else {
this.$message.error(res.msg || '获取装备分类失败')
}
} catch (error) {
this.$message.error('获取装备分类数据失败:' + (error.message || '未知错误'))
}
},
// 新增:递归处理工具分类节点(限制六级)
processToolTree(data, currentLevel = 1) {
if (currentLevel > 6) return []
return data.map(item => {
const processedItem = { ...item }
if (item.children && item.children.length > 0 && currentLevel < 6) {
processedItem.children = this.processToolTree(item.children, currentLevel + 1)
} else {
delete processedItem.children // 超过六级移除子节点
}
return processedItem
})
},
// 新增:获取工具分类树数据
async getToolTree() {
try {
const res = await getTreeSelectApi()
if (res.code === 200) {
let rawData = res.data || []
this.toolTreeData = this.processToolTree(rawData)
} else {
this.$message.error(res.msg || '获取工具分类失败')
}
} catch (error) {
this.$message.error('获取工具分类数据失败:' + (error.message || '未知错误'))
}
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .red {
color: red; /* Element UI官方危险色比纯red更贴合UI风格 */
font-weight: 500; /* 可选:加粗突出告警文本 */
}
/* 六级分类级联选择器样式优化 */
::v-deep .six-level-cascader .el-cascader-menu {
max-height: 300px;
overflow-y: auto;
}
::v-deep .six-level-cascader .el-cascader-menu__item {
position: relative;
transition: all 0.2s;
}
/* 各级分类缩进差异化 */
::v-deep .six-level-cascader .el-cascader-menu[data-level='1'] .el-cascader-menu__item {
padding-left: 20px;
font-weight: 500;
}
::v-deep .six-level-cascader .el-cascader-menu[data-level='2'] .el-cascader-menu__item {
padding-left: 35px;
font-weight: 400;
}
::v-deep .six-level-cascader .el-cascader-menu[data-level='3'] .el-cascader-menu__item {
padding-left: 50px;
font-size: 13px;
}
::v-deep .six-level-cascader .el-cascader-menu[data-level='4'] .el-cascader-menu__item {
padding-left: 65px;
font-size: 13px;
color: #666;
}
::v-deep .six-level-cascader .el-cascader-menu[data-level='5'] .el-cascader-menu__item {
padding-left: 80px;
font-size: 12px;
color: #888;
}
::v-deep .six-level-cascader .el-cascader-menu[data-level='6'] .el-cascader-menu__item {
padding-left: 95px;
font-size: 12px;
color: #999;
background-color: #f8f9fa;
}
/* 隐藏七级及以上分类 */
::v-deep .six-level-cascader .el-cascader-menu[data-level='7'] .el-cascader-menu__item {
display: none;
}
/* 滚动条样式优化 */
::v-deep .six-level-cascader .el-cascader-menu::-webkit-scrollbar {
width: 6px;
}
::v-deep .six-level-cascader .el-cascader-menu::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
::v-deep .six-level-cascader .el-cascader-menu::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 3px;
}
/* 表单项间距优化 */
.el-form-item {
margin-bottom: 15px;
}
</style>