退役页面

This commit is contained in:
syruan 2025-11-16 23:55:09 +08:00
parent 9b7e30772f
commit e7d6535987
7 changed files with 1451 additions and 0 deletions

View File

@ -0,0 +1,54 @@
import request from '@/utils/request'
// 获取退役申请列表
export const getRetireApplyListAPI = (data) => {
return request({
url: '/material-mall/deviceRetireApply/list',
method: 'GET',
params: data,
})
}
// 获取任务明细(装备和工具列表)
export const getRetireApplyDetailAPI = (id) => {
return request({
url: `/material-mall/deviceRetireApply/detail/${id}`,
method: 'GET',
})
}
// 获取在修装备和工具列表(统一接口)
export const getScrapItemListAPI = (data) => {
return request({
url: '/material-mall/deviceRetireApply/scrapItemList',
method: 'GET',
params: data,
})
}
// 提交退役申请任务(包含创建任务和保存明细)
export const submitRetireApplyTaskAPI = (data) => {
return request({
url: '/material-mall/deviceRetireApply/submitTask',
method: 'POST',
data: data,
})
}
// 删除退役申请任务
export const deleteRetireApplyTaskAPI = (id) => {
return request({
url: `/material-mall/deviceRetireApply/deleteTask/${id}`,
method: 'DELETE',
})
}
// 批量审批通过reviewStatus字段区分通过或驳回
export const auditRetireApplyBatchAPI = (data) => {
return request({
url: '/material-mall/deviceRetireApply/audit',
method: 'POST',
data: data,
})
}

View File

@ -267,6 +267,39 @@ export const dynamicRoutes = [
meta: { title: '修改生成配置', activeMenu: '/tool/gen' }
}
]
},
{
path: '/equipment/retire-apply',
component: Layout,
hidden: true,
permissions: ['system:dict:list'],
children: [
{
path: 'index',
component: () => import('@/views/EquipmentRetireApply/index'),
name: 'RetireApply',
meta: { title: '退役申请', activeMenu: '/equipment/retire-apply' }
},
{
path: 'detail/:id',
component: () => import('@/views/EquipmentRetireApply/detail'),
name: 'RetireApplyDetail',
meta: { title: '退役申请明细', activeMenu: '/equipment/retire-apply' }
},
{
path: 'audit',
component: () => import('@/views/EquipmentRetireApply/audit'),
name: 'RetireApplyAudit',
meta: { title: '退役申请审核', activeMenu: '/equipment/retire-apply' }
},
{
path: 'audit-detail/:id',
component: () => import('@/views/EquipmentRetireApply/audit-detail'),
name: 'RetireApplyAuditDetail',
meta: { title: '退役申请审核明细', activeMenu: '/equipment/retire-apply' }
}
]
}
]

View File

@ -0,0 +1,305 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>退役申请审核</span>
</div>
<!-- 基本信息 -->
<el-form ref="baseForm" :model="baseInfo" label-width="120px" size="small">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请单号">
<span>{{ baseInfo.code }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务状态">
<el-tag :type="getStatusType()">
{{ getStatusLabel() }}
</el-tag>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请人">
<span>{{ baseInfo.createUser }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="申请时间">
<span>{{ baseInfo.createTime }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 装备和工具列表 -->
<div class="detail-section">
<div class="section-header">
<span>申请明细</span>
</div>
<el-table ref="detailTable" :data="detailList" style="width: 100%" border stripe size="small" fit @selection-change="onSelectionChange">
<el-table-column type="selection" width="50" :selectable="row => !row.reviewStatus || (row.reviewStatus !== '1' && row.reviewStatus !== '2')" />
<el-table-column align="center" type="index" label="序号" width="80" />
<el-table-column align="center" prop="type" label="分类" width="100" />
<el-table-column align="center" prop="typeName" label="类目" min-width="100" />
<el-table-column align="center" prop="typeModelName" label="规格型号" width="150" />
<el-table-column align="center" prop="manageMode" label="管理模式" width="120" />
<el-table-column align="center" prop="devCode" label="设备编码" min-width="120" />
<el-table-column align="center" prop="scrapQuantity" label="申请报废数量" width="120" />
<el-table-column align="center" prop="retireReason" label="退役原因" min-width="120" show-overflow-tooltip />
<el-table-column align="center" label="报废附件" width="120">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="onHandleViewAttachment(scope.row)">
查看附件
</el-button>
</template>
</el-table-column>
<el-table-column align="center" prop="reviewStatus" label="审批状态" width="100">
<template slot-scope="scope">
<el-tag :type="getReviewStatusType(scope.row.reviewStatus)">
{{ getReviewStatusLabel(scope.row.reviewStatus) }}
</el-tag>
</template>
</el-table-column>
</el-table>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<el-button type="success" @click="onHandleApproveBatch">批量通过</el-button>
<el-button type="danger" @click="onHandleRejectBatch">批量驳回</el-button>
<el-button @click="onHandleCancel">返回</el-button>
</div>
</el-card>
</div>
</template>
<script>
import { getRetireApplyDetailAPI, auditRetireApplyBatchAPI } from '@/api/EquipmentRetireApply/index.js'
export default {
data() {
return {
baseInfo: {
id: '',
code: '',
reviewStatus: '1',
createUser: '',
createTime: ''
},
detailList: [],
selectedRows: []
}
},
methods: {
async getAuditDetail() {
const id = this.$route.params.id
// query
const taskInfoStr = this.$route.query.taskInfo
if (taskInfoStr) {
const taskInfo = JSON.parse(taskInfoStr)
this.baseInfo = {
id: taskInfo.id,
code: taskInfo.code,
reviewStatus: taskInfo.reviewStatus,
createUser: taskInfo.createUser,
createTime: taskInfo.createTime
}
}
// API
const res = await getRetireApplyDetailAPI(id)
const data = res.data || []
//
this.detailList = data.map(item => ({
id: item.id,
keyId: item.keyId,
type: item.type,
typeId: item.typeId,
devType: item.devType,
groupName: item.groupName,
typeName: item.typeName,
typeModelName: item.typeModelName,
manageMode: item.manageMode,
devCode: item.devCode,
code: item.code,
inStockNum: item.inStockNum,
scrapQuantity: item.scrapNum,
retireReason: item.reasonVal,
attachments: item.bmFileInfos || [],
reviewStatus: item.reviewStatus //
}))
},
onSelectionChange(selection) {
// reviewStatus'1''2'
this.selectedRows = selection.filter(row => !row.reviewStatus || (row.reviewStatus !== '1' && row.reviewStatus !== '2'))
},
onHandleViewAttachment(row) {
this.$message.info(`查看 ${row.name} 的附件`)
//
},
async onHandleApproveBatch() {
if (this.selectedRows.length === 0) {
this.$message.warning('请先选择要审核的明细')
return
}
this.$confirm('确定批量通过选中的明细吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
//
const submitData = {
//
id: this.baseInfo.id,
code: this.baseInfo.code,
//
toBeScrapList: this.selectedRows.map(row => ({
id: row.id,
type: row.type,
typeId: row.typeId,
devCode: row.devCode,
scrapNum: row.scrapQuantity,
reviewStatus: '1' // 1
}))
}
await auditRetireApplyBatchAPI(submitData)
this.$message.success('批量通过成功')
this.getAuditDetail()
} catch (error) {
this.$message.error('批量通过失败')
}
}).catch(() => {})
},
async onHandleRejectBatch() {
if (this.selectedRows.length === 0) {
this.$message.warning('请先选择要审核的明细')
return
}
this.$confirm('确定批量驳回选中的明细吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
try {
//
const submitData = {
//
id: this.baseInfo.id,
code: this.baseInfo.code,
//
toBeScrapList: this.selectedRows.map(row => ({
id: row.id,
type: row.type,
typeId: row.typeId,
devCode: row.devCode,
scrapNum: row.scrapQuantity,
reviewStatus: '2' // 2
}))
}
await auditRetireApplyBatchAPI(submitData)
this.$message.success('批量驳回成功')
this.getAuditDetail()
} catch (error) {
this.$message.error('批量驳回失败')
}
}).catch(() => {})
},
onHandleCancel() {
this.$router.back()
},
getStatusLabel() {
//
if (this.detailList.length === 0) {
return '待审批'
}
//
const processedCount = this.detailList.filter(item => item.reviewStatus === '1' || item.reviewStatus === '2').length
const totalCount = this.detailList.length
if (processedCount === 0) {
//
return '待审批'
} else if (processedCount === totalCount) {
//
return '已审批'
} else {
//
return '审批中'
}
},
getStatusType() {
//
const label = this.getStatusLabel()
const typeMap = {
'待审批': 'warning',
'审批中': 'info',
'已审批': 'success'
}
return typeMap[label] || 'info'
},
getReviewStatusLabel(status) {
const statusMap = {
'0': '待审批',
'1': '已通过',
'2': '已驳回'
}
return statusMap[status] || '待审批'
},
getReviewStatusType(status) {
const typeMap = {
'0': 'warning',
'1': 'success',
'2': 'danger'
}
return typeMap[status] || 'warning'
}
},
created() {
this.getAuditDetail()
}
}
</script>
<style lang="scss" scoped>
.box-card {
margin: 20px;
}
.detail-section {
margin: 30px 0;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
font-weight: 600;
font-size: 14px;
}
}
.action-buttons {
text-align: center;
margin-top: 30px;
}
</style>

View File

@ -0,0 +1,231 @@
<template>
<div class="app-container">
<el-row>
<el-form ref="queryForm" size="small" label-width="auto" :model="queryParams">
<el-card class="search-box">
<el-row :gutter="20" style="display: flex; justify-content: space-between">
<el-col :span="5">
<el-form-item label="任务状态" prop="reviewStatus">
<el-select
v-model="queryParams.reviewStatus"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="待审批" value="0" />
<el-option label="审批中" value="1" />
<el-option label="审批完成" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请日期范围" prop="dateRange">
<el-date-picker
v-model="queryParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="14" style="text-align: right;">
<el-button type="primary" icon="el-icon-search" size="mini" @click="onHandleQuery">
查询
</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="onHandleReset">重置</el-button>
</el-col>
</el-row>
</el-card>
</el-form>
<el-card class="content-box">
<div class="table-container">
<el-table :data="tableData" style="width: 100%" border stripe height="100%" fit>
<el-table-column align="center" show-overflow-tooltip type="index" label="序号" width="50" />
<el-table-column align="center" show-overflow-tooltip prop="code" label="退役单号" />
<el-table-column align="center" show-overflow-tooltip prop="equipmentNum" label="退役装备数" />
<el-table-column align="center" show-overflow-tooltip prop="toolNum" label="退役工具数" />
<el-table-column align="center" show-overflow-tooltip prop="reviewStatus" label="任务状态">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.reviewStatus)">
{{ getStatusLabel(scope.row.reviewStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" show-overflow-tooltip prop="createUser" label="申请人" />
<el-table-column align="center" show-overflow-tooltip prop="createTime" label="申请时间" />
<el-table-column align="center" show-overflow-tooltip label="操作" width="100">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="onHandleAudit(scope.row)">审核</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-wrapper">
<pagination
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getRetireApplyAuditList"
/>
</div>
</el-card>
</el-row>
</div>
</template>
<script>
import { getRetireApplyListAPI } from '@/api/EquipmentRetireApply/index.js'
import pagination from '@/components/Pagination'
export default {
components: {
pagination
},
data() {
return {
queryParams: {
reviewStatus: undefined,
dateRange: undefined,
pageNum: 1,
pageSize: 10
},
tableData: [],
total: 0
}
},
methods: {
//
async getRetireApplyAuditList() {
const params = {
...this.queryParams,
startDate: this.queryParams.dateRange ? this.queryParams.dateRange[0] : undefined,
endDate: this.queryParams.dateRange ? this.queryParams.dateRange[1] : undefined,
dateRange: undefined
}
const res = await getRetireApplyListAPI(params)
this.tableData = res.rows || []
this.total = res.total || 0
},
//
onHandleQuery() {
this.queryParams.pageNum = 1
this.getRetireApplyAuditList()
},
//
onHandleReset() {
this.queryParams = {
reviewStatus: undefined,
dateRange: undefined,
pageNum: 1,
pageSize: 10
}
this.getRetireApplyAuditList()
},
//
onHandleAudit(row) {
this.$router.push({
name: 'RetireApplyAuditDetail',
params: { id: row.id },
query: { taskInfo: JSON.stringify(row) }
})
},
//
getStatusLabel(status) {
const statusMap = {
'0': '待审批',
'1': '审批中',
'2': '审批完成'
}
return statusMap[status] || '未知'
},
//
getStatusType(status) {
const typeMap = {
'0': 'warning',
'1': 'info',
'2': 'success'
}
return typeMap[status] || 'info'
}
},
created() {
this.getRetireApplyAuditList()
}
}
</script>
<style lang="scss" scoped>
.search-box {
margin-bottom: 20px;
border-radius: 8px;
padding: 0;
}
.content-box {
border-radius: 8px;
height: calc(100vh - 260px);
display: flex;
flex-direction: column;
overflow: hidden;
::v-deep .el-card__body {
display: flex !important;
flex-direction: column !important;
height: 100% !important;
padding: 20px;
}
.table-container {
flex: 1;
overflow: hidden;
margin-bottom: 0;
min-height: 0;
display: flex;
flex-direction: column;
}
.pagination-wrapper {
flex-shrink: 0;
padding-top: 6px;
margin-top: auto;
::v-deep .pagination-container {
padding: 0px 20px !important;
margin-bottom: 30px;
}
}
::v-deep .el-table {
&.el-table--striped .el-table__body {
tr.el-table__row--striped td {
background-color: #F6FBFA !important;
}
}
.el-table__header {
background: #E9F0EE;
th {
background: #E9F0EE !important;
color: #606266;
font-weight: 600;
height: 50px;
}
}
&.el-table--striped .el-table__body tr.el-table__row:hover>td.el-table__cell {
background-color: #CCF1E9 !important;
}
}
}
</style>

View File

@ -0,0 +1,200 @@
<template>
<el-dialog
title="添加装备/工具"
:visible.sync="visible"
width="80%"
@close="onClose"
>
<!-- 搜索条件 -->
<el-form ref="queryForm" size="small" label-width="auto" :model="queryParams">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入名称" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="分类" prop="type">
<el-select v-model="queryParams.type" placeholder="请选择分类" clearable>
<el-option label="装备" value="装备" />
<el-option label="工具" value="工具" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" style="text-align: right;">
<el-button type="primary" size="small" @click="onHandleQuery">查询</el-button>
<el-button size="small" @click="onHandleReset">重置</el-button>
</el-col>
</el-row>
</el-form>
<!-- 在修装备/工具列表 -->
<el-table
ref="itemTable"
:data="itemList"
style="width: 100%"
border
stripe
size="small"
fit
@selection-change="onSelectionChange"
>
<el-table-column type="selection" width="50" />
<el-table-column align="center" type="index" label="序号" width="100" />
<el-table-column align="center" prop="type" label="分类" min-width="70" />
<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="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: center; 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="onHandleConfirm">确定</el-button>
</span>
</el-dialog>
</template>
<script>
import { getScrapItemListAPI } from '@/api/EquipmentRetireApply/index.js'
export default {
props: {
existingItems: {
type: Array,
default: () => []
}
},
data() {
return {
visible: false,
queryParams: {
name: '',
type: '',
pageNum: 1,
pageSize: 10
},
itemList: [],
total: 0,
selectedItems: [],
allSelectedItems: [] //
}
},
watch: {
'queryParams.pageNum'() {
this.getItemList()
},
'queryParams.pageSize'() {
this.queryParams.pageNum = 1
this.getItemList()
}
},
methods: {
open() {
this.visible = true
this.getItemList()
},
async getItemList() {
try {
const res = await getScrapItemListAPI(this.queryParams)
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: '',
type: '',
pageNum: 1,
pageSize: 10
}
this.getItemList()
},
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)
},
onHandleConfirm() {
if (this.allSelectedItems.length === 0) {
this.$message.warning('请选择至少一项')
return
}
//
const invalidItems = this.allSelectedItems.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
}
// 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.allSelectedItems)
this.visible = false
this.selectedItems = []
this.allSelectedItems = []
},
onClose() {
this.selectedItems = []
this.allSelectedItems = []
}
}
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,367 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>{{ isNew ? '新增退役申请' : '退役申请明细' }}</span>
</div>
<!-- 基本信息 -->
<el-form ref="baseForm" :model="baseInfo" label-width="120px" size="small">
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请单号">
<span v-if="!isNew">{{ baseInfo.code }}</span>
<span v-else>新增</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务状态">
<el-tag :type="getStatusType()">
{{ getStatusLabel() }}
</el-tag>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="申请人">
<span>{{ baseInfo.createUser }}</span>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="申请时间">
<span>{{ baseInfo.createTime }}</span>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 装备和工具列表 -->
<div class="detail-section">
<div class="section-header">
<span>申请明细</span>
<el-button type="primary" size="small" icon="el-icon-plus" :disabled="!canEdit" @click="onHandleAddItem">
添加装备/工具
</el-button>
</div>
<el-table :data="detailList" style="width: 100%" border stripe size="small" fit>
<el-table-column align="center" type="index" label="序号" width="70" />
<el-table-column align="center" prop="type" label="分类" width="90" />
<el-table-column align="center" prop="typeName" label="类目" width="180" />
<el-table-column align="center" prop="typeModelName" label="规格型号" width="180" />
<el-table-column align="center" prop="manageMode" label="管理模式" width="120" />
<el-table-column align="center" prop="devCode" label="设备编码" min-width="120" />
<el-table-column v-if="isNew" align="center" prop="inStockNum" label="在库数量" width="80" />
<el-table-column align="center" prop="scrapQuantity" label="申请报废数量" width="120" />
<el-table-column align="center" prop="retireReason" label="退役原因" width="180">
<template slot-scope="scope">
<el-input
v-model="scope.row.retireReason"
placeholder="请输入退役原因"
size="small"
maxlength="20"
show-word-limit
:disabled="!canEdit"
/>
</template>
</el-table-column>
<el-table-column align="center" label="报废附件" width="140">
<template slot-scope="scope">
<div style="display: flex;align-items: center;justify-content: center;">
<el-upload
ref="upload"
:limit="1"
:headers="upload.headers"
:action="upload.url"
:show-file-list="false"
accept=".png, .jpg, .jpeg, .pdf, .doc, .docx"
:on-success="(res) => handleFileSuccess(res, scope.row)"
:auto-upload="true"
:disabled="!canEdit"
>
<el-button type="primary" size="mini" :disabled="!canEdit">上传附件</el-button>
</el-upload>
<el-button v-if="scope.row.bmFileInfos && scope.row.bmFileInfos.length > 0" type="text" size="mini" @click="picturePreview(scope.row)">
查看
</el-button>
</div>
</template>
</el-table-column>
<el-table-column align="center" label="操作" width="100">
<template slot-scope="scope">
<el-button type="danger" size="mini" :disabled="!canEdit" @click="onHandleDeleteItem(scope.row)">
删除
</el-button>
</template>
</el-table-column>
</el-table>
</div>
<!-- 操作按钮 -->
<div class="action-buttons">
<el-button type="primary" :disabled="!canEdit" @click="onHandleSubmit">确认申请</el-button>
<el-button @click="onHandleCancel">返回</el-button>
</div>
</el-card>
<!-- 添加装备/工具弹窗 -->
<add-item-dialog
ref="addItemDialog"
:existing-items="detailList"
@confirm="onAddItemConfirm"
/>
</div>
</template>
<script>
import { getRetireApplyDetailAPI, submitRetireApplyTaskAPI } from '@/api/EquipmentRetireApply/index.js'
import AddItemDialog from './components/AddItemDialog'
import { getToken } from '@/utils/auth'
export default {
components: {
AddItemDialog
},
data() {
return {
isNew: false,
baseInfo: {
id: '',
code: '',
reviewStatus: '1',
createUser: '',
createTime: ''
},
detailList: [],
fileData: {},
upload: {
headers: { Authorization: 'Bearer ' + getToken() },
url: process.env.VUE_APP_BASE_API + '/file/upload'
}
}
},
computed: {
//
canEdit() {
if (this.isNew) {
return true
}
const status = this.getStatusLabel()
return status === '待审批'
}
},
methods: {
async getDetail() {
const id = this.$route.params.id
if (id === 'new') {
this.isNew = true
this.baseInfo.createUser = this.$store.state.user?.nickName || '当前用户'
this.baseInfo.createTime = new Date().toLocaleString()
} else {
// query
const taskInfoStr = this.$route.query.taskInfo
if (taskInfoStr) {
const taskInfo = JSON.parse(taskInfoStr)
this.baseInfo = {
id: taskInfo.id,
code: taskInfo.code,
reviewStatus: taskInfo.reviewStatus,
createUser: taskInfo.createUser,
createTime: taskInfo.createTime
}
}
// API
const res = await getRetireApplyDetailAPI(id)
const data = res.data || []
//
this.detailList = data.map(item => ({
id: item.id,
keyId: item.keyId,
type: item.type,
typeId: item.typeId,
devType: item.devType,
groupName: item.groupName,
typeName: item.typeName,
typeModelName: item.typeModelName,
manageMode: item.manageMode,
devCode: item.devCode,
code: item.code,
inStockNum: item.inStockNum,
scrapQuantity: item.scrapNum,
retireReason: item.reasonVal,
bmFileInfos: item.bmFileInfos || [],
reviewStatus: item.reviewStatus //
}))
}
},
onHandleAddItem() {
this.$refs.addItemDialog.open()
},
async onAddItemConfirm(items) {
// bmFileInfos
const itemsWithFileInfo = items.map(item => ({
...item,
bmFileInfos: item.bmFileInfos || []
}))
this.detailList.push(...itemsWithFileInfo)
},
onHandleDeleteItem(row) {
this.$confirm('确定删除该项吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
const index = this.detailList.indexOf(row)
if (index > -1) {
this.detailList.splice(index, 1)
}
this.$message.success('删除成功')
}).catch(() => {})
},
async onHandleSubmit() {
if (this.detailList.length === 0) {
this.$message.warning('请至少添加一项装备或工具')
return
}
try {
//
const submitData = {
...this.baseInfo,
operationType: this.isNew ? 'add' : 'edit', //
toBeScrapList: this.detailList.map(item => ({
keyId: item.keyId,
devCode: item.devCode,
type: item.type,
typeId: item.typeId,
devType: item.devType,
scrapNum: item.scrapQuantity,
reasonVal: item.retireReason,
bmFileInfos: item.bmFileInfos || []
}))
}
await submitRetireApplyTaskAPI(submitData)
this.$message.success('申请提交成功')
this.$router.push('/equipment/retire-apply/index')
} catch (error) {
this.$message.error('提交失败')
}
},
onHandleCancel() {
this.$router.back()
},
getStatusLabel() {
//
if (this.isNew) {
return '待审批'
}
//
if (this.detailList.length === 0) {
return '待审批'
}
//
const processedCount = this.detailList.filter(item => item.reviewStatus === '1' || item.reviewStatus === '2').length
const totalCount = this.detailList.length
if (processedCount === 0) {
//
return '待审批'
} else if (processedCount === totalCount) {
//
return '审批完成'
} else {
//
return '审批中'
}
},
getStatusType() {
//
const label = this.getStatusLabel()
const typeMap = {
'待审批': 'warning',
'审批中': 'info',
'审批完成': 'success'
}
return typeMap[label] || 'info'
},
//
beforeFileUpload(row) {
this.fileData = row
},
//
handleFileSuccess(response, row) {
if (response.code === 200) {
// bmFileInfos
if (!row.bmFileInfos) {
row.bmFileInfos = []
}
//
const fileObj = {
name: response.data.name,
url: response.data.url
}
row.bmFileInfos = [fileObj]
this.$message.success('文件上传成功')
} else {
this.$message.error('文件上传失败')
}
},
//
picturePreview(row) {
if (row.bmFileInfos && row.bmFileInfos.length > 0) {
const file = row.bmFileInfos[0]
const parts = file.name.split('.')
const extension = parts.pop()
if (extension === 'doc' || extension === 'docx' || extension === 'pdf') {
window.open(file.url, file.name)
} else {
this.$message.info('预览图片: ' + file.name)
}
}
}
},
created() {
this.getDetail()
}
}
</script>
<style lang="scss" scoped>
.box-card {
margin: 20px;
}
.detail-section {
margin: 30px 0;
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
font-weight: 600;
font-size: 14px;
}
}
.action-buttons {
text-align: center;
margin-top: 30px;
}
</style>

View File

@ -0,0 +1,261 @@
<template>
<div class="app-container">
<el-row>
<el-form ref="queryForm" size="small" label-width="auto" :model="queryParams">
<el-card class="search-box">
<el-row :gutter="20" style="display: flex; justify-content: space-between">
<el-col :span="5">
<el-form-item label="任务状态" prop="reviewStatus">
<el-select
v-model="queryParams.reviewStatus"
placeholder="请选择状态"
clearable
style="width: 100%"
>
<el-option label="待审批" value="0" />
<el-option label="审批中" value="1" />
<el-option label="审批完成" value="2" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="申请日期范围" prop="dateRange">
<el-date-picker
v-model="queryParams.dateRange"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="14" style="text-align: right;">
<el-button type="primary" icon="el-icon-search" size="mini" @click="onHandleQuery">
查询
</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="onHandleReset">重置</el-button>
<el-button type="primary" icon="el-icon-plus" size="mini" @click="onHandleAdd">新增</el-button>
</el-col>
</el-row>
</el-card>
</el-form>
<el-card class="content-box">
<div class="table-container">
<el-table :data="tableData" style="width: 100%" border stripe height="100%" fit>
<el-table-column align="center" show-overflow-tooltip type="index" label="序号" width="50" />
<el-table-column align="center" show-overflow-tooltip prop="code" label="退役单号" />
<el-table-column align="center" show-overflow-tooltip prop="equipmentNum" label="退役装备数" />
<el-table-column align="center" show-overflow-tooltip prop="toolNum" label="退役工具数" />
<el-table-column align="center" show-overflow-tooltip prop="reviewStatus" label="任务状态">
<template slot-scope="scope">
<el-tag :type="getStatusType(scope.row.reviewStatus)">
{{ getStatusLabel(scope.row.reviewStatus) }}
</el-tag>
</template>
</el-table-column>
<el-table-column align="center" show-overflow-tooltip prop="createUser" label="申请人" />
<el-table-column align="center" show-overflow-tooltip prop="createTime" label="申请时间" />
<el-table-column align="center" show-overflow-tooltip label="操作" width="250">
<template slot-scope="scope">
<el-button type="primary" size="mini" @click="onHandleView(scope.row)">查看</el-button>
<el-button v-if="scope.row.reviewStatus === '0'" type="primary" size="mini" @click="onHandleEdit(scope.row)">编辑</el-button>
<el-button v-if="scope.row.reviewStatus === '0'" type="danger" size="mini" @click="onHandleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
<div class="pagination-wrapper">
<pagination
:total="total"
:page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize"
@pagination="getRetireApplyList"
/>
</div>
</el-card>
</el-row>
</div>
</template>
<script>
import { getRetireApplyListAPI, deleteRetireApplyTaskAPI } from '@/api/EquipmentRetireApply/index.js'
import pagination from '@/components/Pagination'
export default {
components: {
pagination
},
data() {
return {
queryParams: {
reviewStatus: undefined,
dateRange: undefined,
pageNum: 1,
pageSize: 10
},
tableData: [],
total: 0
}
},
methods: {
// 退
async getRetireApplyList() {
const params = {
...this.queryParams,
startDate: this.queryParams.dateRange ? this.queryParams.dateRange[0] : undefined,
endDate: this.queryParams.dateRange ? this.queryParams.dateRange[1] : undefined,
dateRange: undefined
}
const res = await getRetireApplyListAPI(params)
this.tableData = res.rows || []
this.total = res.total || 0
},
//
onHandleQuery() {
this.queryParams.pageNum = 1
this.getRetireApplyList()
},
//
onHandleReset() {
this.queryParams = {
reviewStatus: undefined,
dateRange: undefined,
pageNum: 1,
pageSize: 10
}
this.getRetireApplyList()
},
//
onHandleAdd() {
this.$router.push('/equipment/retire-apply/detail/new')
},
// /
onHandleView(row) {
this.$router.push({
name: 'RetireApplyDetail',
params: { id: row.id },
query: { taskInfo: JSON.stringify(row) }
})
},
//
onHandleEdit(row) {
this.$router.push({
name: 'RetireApplyDetail',
params: { id: row.id },
query: { taskInfo: JSON.stringify(row) }
})
},
//
async onHandleDelete(row) {
this.$confirm('确定删除该退役申请吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
await deleteRetireApplyTaskAPI(row.id)
this.$message.success('删除成功')
this.getRetireApplyList()
}).catch(() => {})
},
//
getStatusLabel(status) {
const statusMap = {
'0': '待审批',
'1': '审批中',
'2': '审批完成'
}
return statusMap[status] || '未知'
},
//
getStatusType(status) {
const typeMap = {
'0': 'warning',
'1': 'info',
'2': 'success'
}
return typeMap[status] || 'info'
}
},
created() {
this.getRetireApplyList()
}
}
</script>
<style lang="scss" scoped>
.search-box {
margin-bottom: 20px;
border-radius: 8px;
padding: 0;
}
.content-box {
border-radius: 8px;
height: calc(100vh - 260px);
display: flex;
flex-direction: column;
overflow: hidden;
::v-deep .el-card__body {
display: flex !important;
flex-direction: column !important;
height: 100% !important;
padding: 20px;
}
.table-container {
flex: 1;
overflow: hidden;
margin-bottom: 0;
min-height: 0;
display: flex;
flex-direction: column;
}
.pagination-wrapper {
flex-shrink: 0;
padding-top: 6px;
margin-top: auto;
::v-deep .pagination-container {
padding: 0px 20px !important;
margin-bottom: 30px;
}
}
::v-deep .el-table {
&.el-table--striped .el-table__body {
tr.el-table__row--striped td {
background-color: #F6FBFA !important;
}
}
.el-table__header {
background: #E9F0EE;
th {
background: #E9F0EE !important;
color: #606266;
font-weight: 600;
height: 50px;
}
}
&.el-table--striped .el-table__body tr.el-table__row:hover>td.el-table__cell {
background-color: #CCF1E9 !important;
}
}
}
</style>