<template>
|
<div class="page">
|
<div class="page-title">
|
<div>
|
<h2>XCB助理审核</h2>
|
<p>分配承修单位、跟踪技术队和要求完工日期,审核后进入CMB领导审批</p>
|
</div>
|
</div>
|
|
<div class="toolbar query-toolbar">
|
<span class="filter-label">X号</span>
|
<el-select v-model="query.xNo" placeholder="全部" clearable style="width:100px">
|
<el-option v-for="item in xNumbers" :key="item" :label="item" :value="item"></el-option>
|
</el-select>
|
<span class="filter-label">T队专业</span>
|
<el-select v-model="query.teamMajor" placeholder="全部" clearable style="width:130px">
|
<el-option v-for="item in teamMajors" :key="item.id" :label="item.name" :value="item.name"></el-option>
|
</el-select>
|
<span class="filter-label">工程专业</span>
|
<el-select v-model="query.engineeringMajor" placeholder="全部" clearable style="width:130px">
|
<el-option v-for="item in engineeringMajors" :key="item.id" :label="item.name" :value="item.name"></el-option>
|
</el-select>
|
<span class="filter-label">上报单位</span>
|
<el-input v-model="query.reportUnit" placeholder="单位名称" clearable style="width:150px" @keyup.enter.native="load"></el-input>
|
<span class="filter-label">负责人</span>
|
<el-input v-model="query.owner" placeholder="负责人" clearable style="width:110px" @keyup.enter.native="load"></el-input>
|
<span class="filter-label">上报日期</span>
|
<el-date-picker
|
v-model="query.reportDateRange"
|
type="daterange"
|
value-format="yyyy-MM-dd"
|
range-separator="至"
|
start-placeholder="开始日期"
|
end-placeholder="结束日期"
|
style="width:300px"
|
></el-date-picker>
|
<span class="filter-label">承修单位</span>
|
<el-select v-model="query.contractorName" placeholder="全部" clearable filterable style="width:170px">
|
<el-option v-for="item in contractors" :key="item.id" :label="item.shortName || item.name" :value="item.name"></el-option>
|
</el-select>
|
<span class="filter-label">故障性质</span>
|
<el-select v-model="query.faultNature" placeholder="全部" clearable style="width:100px">
|
<el-option v-for="item in natures" :key="item" :label="item" :value="item"></el-option>
|
</el-select>
|
<span class="filter-label">任务状态</span>
|
<el-select v-model="query.status" placeholder="全部" clearable style="width:180px">
|
<el-option v-for="(meta, key) in taskStatuses" :key="key" :label="meta.text" :value="key"></el-option>
|
</el-select>
|
<el-input v-model="query.keyword" placeholder="故障编号/装备名称/工程名称及损坏情况" clearable style="width:320px" @keyup.enter.native="load"></el-input>
|
<el-button type="primary" icon="el-icon-search" @click="load">查询</el-button>
|
<el-button icon="el-icon-refresh-left" @click="resetQuery">重置</el-button>
|
<el-button icon="el-icon-refresh" @click="load">刷新</el-button>
|
</div>
|
|
<div class="toolbar action-toolbar">
|
<span class="selection-tip">已选择 {{ selection.length }} 条</span>
|
<div class="spacer"></div>
|
<el-button type="primary" icon="el-icon-s-check" :disabled="selection.length === 0" @click="openReview">审核</el-button>
|
<el-button icon="el-icon-edit" :disabled="selection.length !== 1" @click="editSelected">修改</el-button>
|
<el-button type="danger" plain icon="el-icon-remove-outline" :disabled="selection.length === 0" @click="openCancel">销项</el-button>
|
</div>
|
|
<div class="table-panel">
|
<el-table :data="rows" border stripe height="calc(100vh - 355px)" :header-cell-style="{ textAlign: 'center' }" @selection-change="selection = $event">
|
<el-table-column type="selection" width="46" :selectable="canProcess"></el-table-column>
|
<el-table-column prop="taskStatus" label="任务状态" width="145" fixed>
|
<template slot-scope="{ row }"><el-tag size="mini" :type="taskMeta(row.taskStatus).type">{{ taskMeta(row.taskStatus).text }}</el-tag></template>
|
</el-table-column>
|
<el-table-column prop="faultCode" label="故障编号" width="180" fixed></el-table-column>
|
<el-table-column prop="xNo" label="X号" width="64"></el-table-column>
|
<el-table-column prop="equipmentName" label="装备名称" min-width="210" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="parentSystem" label="所属上级系统" min-width="120"></el-table-column>
|
<el-table-column prop="engineeringNameDesc" label="工程名称及损坏情况" min-width="210" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="repairRequirement" label="修理技术要求" min-width="200" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="engineeringMajor" label="工程专业" width="100"></el-table-column>
|
<el-table-column prop="teamMajor" label="T队专业" width="100"></el-table-column>
|
<el-table-column prop="owner" label="负责人" width="90"></el-table-column>
|
<el-table-column prop="reportUnit" label="上报单位" min-width="130"></el-table-column>
|
<el-table-column prop="reportDate" label="上报日期" width="110" align="center"></el-table-column>
|
<el-table-column prop="faultImpact" label="故障影响" width="100"></el-table-column>
|
<el-table-column prop="faultNature" label="故障性质" width="100" align="center"></el-table-column>
|
<el-table-column prop="majorFaultDesc" label="重大故障描述" min-width="200" show-overflow-tooltip></el-table-column>
|
<el-table-column label="是否自修" width="90" align="center">
|
<template slot-scope="{ row }">{{ yesNo(row.isSelfRepair) }}</template>
|
</el-table-column>
|
<el-table-column label="是否涉H" width="90" align="center">
|
<template slot-scope="{ row }">{{ yesNo(row.isHRelated) }}</template>
|
</el-table-column>
|
<el-table-column label="监测项目" width="90" align="center">
|
<template slot-scope="{ row }">{{ yesNo(row.isMonitorItem) }}</template>
|
</el-table-column>
|
<el-table-column prop="monitorValue" label="监测数值" width="110" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="requestedFinishDate" label="要求完工日期" width="120" align="center"></el-table-column>
|
<el-table-column prop="remark" label="备注" min-width="130" show-overflow-tooltip></el-table-column>
|
</el-table>
|
</div>
|
|
<fault-edit-dialog :visible.sync="editVisible" :fault="editingFault" @saved="onFaultSaved"></fault-edit-dialog>
|
|
<el-dialog title="XCB助理审核" :visible.sync="dialogVisible" width="820px" append-to-body>
|
<el-alert :closable="false" type="info" show-icon title="承修单位可多选。排序前7个作为常用承修单位优先显示,失信单位标记提醒。" style="margin-bottom:14px"></el-alert>
|
<el-form :model="form" label-width="105px">
|
<el-form-item label="已选故障">
|
<span class="selected-codes">{{ selectedCodes }}</span>
|
</el-form-item>
|
<el-form-item label="常用承修单位">
|
<div class="contractor-grid">
|
<el-checkbox-group v-model="form.contractorIds">
|
<el-checkbox v-for="item in commonContractors" :key="item.id" :label="item.id" border>
|
{{ item.shortName || item.name }}
|
<el-tag v-if="item.dishonest === 1" size="mini" type="danger">失信</el-tag>
|
</el-checkbox>
|
</el-checkbox-group>
|
</div>
|
<el-collapse v-if="otherContractors.length" style="margin-top:8px">
|
<el-collapse-item :title="'更多承修单位(' + otherContractors.length + ')'">
|
<el-checkbox-group v-model="form.contractorIds">
|
<el-checkbox v-for="item in otherContractors" :key="item.id" :label="item.id" border>{{ item.name }}</el-checkbox>
|
</el-checkbox-group>
|
</el-collapse-item>
|
</el-collapse>
|
</el-form-item>
|
<el-form-item label="跟踪技术队">
|
<el-radio-group v-model="form.trackingTeam">
|
<el-radio-button v-for="item in trackingTeams" :key="item" :label="item">{{ item }}</el-radio-button>
|
</el-radio-group>
|
</el-form-item>
|
<el-form-item label="要求完工日期">
|
<el-date-picker v-model="form.requestedFinishDate" type="date" value-format="yyyy-MM-dd" style="width:220px"></el-date-picker>
|
</el-form-item>
|
<el-form-item label="审核说明">
|
<el-input v-model="form.opinion" type="textarea" :rows="2" placeholder="可填写拆单或器材领用说明"></el-input>
|
</el-form-item>
|
</el-form>
|
<template slot="footer">
|
<el-button @click="dialogVisible = false">取消</el-button>
|
<el-button type="primary" :loading="saving" @click="submitReview">完成审核</el-button>
|
</template>
|
</el-dialog>
|
|
<el-dialog title="故障销项" :visible.sync="cancelVisible" width="560px" append-to-body>
|
<el-form label-width="90px">
|
<el-form-item label="销项故障">
|
<div class="selected-codes">{{ selectedCodes }}</div>
|
</el-form-item>
|
<el-form-item label="销项理由">
|
<el-input v-model="cancelReason" type="textarea" :rows="3" placeholder="请填写销项理由"></el-input>
|
</el-form-item>
|
</el-form>
|
<template slot="footer">
|
<el-button @click="cancelVisible = false">取消</el-button>
|
<el-button type="danger" :loading="cancelling" @click="submitCancel">确认销项</el-button>
|
</template>
|
</el-dialog>
|
</div>
|
</template>
|
<script>
|
import api from '@/api'
|
import { taskStatuses, statusMeta } from '@/utils/dict'
|
import FaultEditDialog from '@/views/fault/FaultEditDialog.vue'
|
|
export default {
|
name: 'XcbReview',
|
components: { FaultEditDialog },
|
data() {
|
return {
|
taskStatuses,
|
query: {
|
keyword: '',
|
status: 'REPORTED_XCB',
|
xNo: '',
|
teamMajor: '',
|
engineeringMajor: '',
|
reportUnit: '',
|
owner: '',
|
reportDateRange: [],
|
contractorName: '',
|
faultNature: ''
|
},
|
rows: [],
|
selection: [],
|
contractors: [],
|
xNumbers: [],
|
teamMajors: [],
|
engineeringMajors: [],
|
natures: ['一般', '重大'],
|
dialogVisible: false,
|
editVisible: false,
|
editingFault: null,
|
cancelVisible: false,
|
cancelReason: '',
|
cancelling: false,
|
saving: false,
|
trackingTeams: ['T01队', 'T02队', 'T03队'],
|
form: { contractorIds: [], trackingTeam: 'T01队', requestedFinishDate: '', opinion: '' }
|
}
|
},
|
computed: {
|
commonContractors() { return this.contractors.slice(0, 7) },
|
otherContractors() { return this.contractors.slice(7) },
|
selectedCodes() { return this.selection.map(item => item.faultCode).join('、') }
|
},
|
created() {
|
this.load()
|
this.loadContractors()
|
this.loadXNumbers()
|
this.loadMajors()
|
},
|
methods: {
|
taskMeta(value) { return statusMeta(taskStatuses, value) },
|
yesNo(value) { return Number(value) === 1 ? '是' : '否' },
|
canProcess(row) { return ['REPORTED_XCB', 'RETURNED'].includes(row.taskStatus) },
|
queryParams() {
|
const range = this.query.reportDateRange || []
|
return {
|
keyword: this.query.keyword,
|
status: this.query.status,
|
xNo: this.query.xNo,
|
teamMajor: this.query.teamMajor,
|
engineeringMajor: this.query.engineeringMajor,
|
reportUnit: this.query.reportUnit,
|
owner: this.query.owner,
|
reportDateStart: range[0] || '',
|
reportDateEnd: range[1] || '',
|
contractorName: this.query.contractorName,
|
faultNature: this.query.faultNature
|
}
|
},
|
load() {
|
api.get('/faults', { params: this.queryParams() }).then(res => { this.rows = res.data || [] })
|
},
|
resetQuery() {
|
this.query = {
|
keyword: '',
|
status: 'REPORTED_XCB',
|
xNo: '',
|
teamMajor: '',
|
engineeringMajor: '',
|
reportUnit: '',
|
owner: '',
|
reportDateRange: [],
|
contractorName: '',
|
faultNature: ''
|
}
|
this.load()
|
},
|
loadContractors() {
|
api.get('/system/contractors').then(res => { this.contractors = res.data || [] })
|
},
|
loadMajors() {
|
api.get('/system/team-majors').then(res => { this.teamMajors = res.data || [] })
|
api.get('/system/engineering-majors').then(res => { this.engineeringMajors = res.data || [] })
|
},
|
loadXNumbers() {
|
api.get('/system/tree', { params: { type: 'product' } }).then(res => {
|
const values = []
|
const walk = nodes => {
|
if (!nodes) return
|
nodes.forEach(node => {
|
if (node.nodeType === 'X_NO' || node.nodeLevel === 2) values.push(node.name)
|
walk(node.children)
|
})
|
}
|
walk(res.data)
|
this.xNumbers = Array.from(new Set(values.filter(Boolean))).sort((a, b) => a.localeCompare(b, 'zh-CN'))
|
})
|
},
|
editSelected() {
|
if (this.selection.length !== 1) return
|
this.editingFault = JSON.parse(JSON.stringify(this.selection[0]))
|
this.editVisible = true
|
},
|
onFaultSaved() {
|
this.editVisible = false
|
this.load()
|
},
|
openReview() {
|
this.form = {
|
ids: this.selection.map(item => item.id),
|
contractorIds: [],
|
trackingTeam: 'T01队',
|
requestedFinishDate: '',
|
opinion: ''
|
}
|
this.dialogVisible = true
|
},
|
submitReview() {
|
if (!this.form.contractorIds.length) return this.$message.warning('至少选择一个承修单位')
|
this.saving = true
|
api.post('/faults/review', this.form).then(() => {
|
this.$message.success('审核完成')
|
this.dialogVisible = false
|
this.load()
|
}).finally(() => { this.saving = false })
|
},
|
openCancel() {
|
this.cancelReason = ''
|
this.cancelVisible = true
|
},
|
submitCancel() {
|
if (!this.cancelReason.trim()) return this.$message.warning('请填写销项理由')
|
this.cancelling = true
|
api.post('/faults/cancel', {
|
ids: this.selection.map(item => item.id),
|
reason: this.cancelReason.trim(),
|
cancelledBy: sessionStorage.getItem('realName') || 'XCB助理'
|
}).then(() => {
|
this.$message.success('销项完成')
|
this.cancelVisible = false
|
this.load()
|
}).finally(() => { this.cancelling = false })
|
}
|
}
|
}
|
</script>
|
<style scoped>
|
.query-toolbar { margin-bottom: 8px; }
|
.query-toolbar ::v-deep .el-range-separator { flex: 0 0 18px; min-width: 18px; }
|
.action-toolbar { min-height: 50px; }
|
.filter-label { margin-left: 4px; color: #4d6073; font-size: 13px; white-space: nowrap; }
|
.selection-tip { color: #6d7f91; font-size: 13px; }
|
.selected-codes { color: #2c5278; font-weight: 600; }
|
.contractor-grid .el-checkbox { margin-right: 8px; margin-bottom: 8px; min-width: 190px; }
|
.contractor-grid .el-tag { margin-left: 6px; }
|
@media (max-width: 900px) {
|
.query-toolbar .el-date-editor { width: 100% !important; }
|
}
|
</style>
|