374 lines
12 KiB
Vue
374 lines
12 KiB
Vue
<template>
|
||
<div class="app-container">
|
||
<el-card style="margin-bottom: 20px">
|
||
<div slot="header" class="clearfix">
|
||
<span>{{ isNew ? '新增退役申请' : '退役申请明细' }}</span>
|
||
</div>
|
||
|
||
<!-- 基本信息 -->
|
||
<el-form ref="baseForm" :model="baseInfo" label-width="70px" inline style="height: 36px" >
|
||
<el-form-item label="申请单号" style="margin-bottom: 0; height: 36px">
|
||
<!-- 申请单号:禁用的输入框 -->
|
||
<el-input
|
||
v-model="baseInfo.code"
|
||
placeholder="无"
|
||
disabled
|
||
:value="!isNew ? baseInfo.code : '新增'"
|
||
style="width: 240px;"
|
||
/>
|
||
</el-form-item>
|
||
<el-form-item label="任务状态">
|
||
<!-- 任务状态:禁用的输入框 + 标签样式 -->
|
||
<el-input
|
||
:value="getStatusLabel()"
|
||
disabled
|
||
style="background: transparent; border: none; padding-left: 0; width: 240px;"
|
||
>
|
||
</el-input>
|
||
</el-form-item>
|
||
<el-form-item label="申请人">
|
||
<!-- 申请人:禁用的输入框 -->
|
||
<el-input v-model="baseInfo.createUser" placeholder="无" disabled style="width: 240px;" />
|
||
</el-form-item>
|
||
<el-form-item label="申请时间">
|
||
<!-- 申请时间:禁用的输入框 -->
|
||
<el-input v-model="baseInfo.createTime" placeholder="无" disabled style="width: 240px;" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</el-card>
|
||
|
||
<!-- 装备和工具列表 -->
|
||
<el-card>
|
||
<div class="detail-section">
|
||
<div class="section-header">
|
||
<el-col :span="4">
|
||
<span style="font-size: 20px; font-weight: 800">申请列表</span>
|
||
</el-col>
|
||
<el-col :span="20" style="display: flex; justify-content: flex-end">
|
||
<el-button type="primary" size="small" :disabled="!canEdit" @click="onHandleAddItem">
|
||
添加装备/工具
|
||
</el-button>
|
||
<!-- 操作按钮 -->
|
||
<el-button type="primary" size="small" :disabled="!canEdit" @click="onHandleSubmit">确认申请</el-button>
|
||
</el-col>
|
||
</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-select
|
||
v-model="scope.row.retireReason"
|
||
placeholder="请选择退役原因"
|
||
size="small"
|
||
:disabled="!canEdit"
|
||
>
|
||
<el-option label="人为" value="人为"></el-option>
|
||
<el-option label="自然" value="自然"></el-option>
|
||
</el-select>
|
||
</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>
|
||
|
||
|
||
</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;
|
||
// 从路由参数中获取 mode
|
||
const mode = this.$route.query.mode;
|
||
// 如果 mode 是 'edit',允许编辑;如果是 'view' 或其他值,不允许编辑
|
||
return mode === 'edit';
|
||
}
|
||
},
|
||
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>
|
||
|