From ffe06be91f95ffd2459ebdb2f9130d1e38d53ea7 Mon Sep 17 00:00:00 2001
From: zzw <228544128@qq.com>
Date: 星期二, 06 十月 2026 18:32:34 +0800
Subject: [PATCH] fix: preserve manually edited menu names
---
emergency-repair-web/src/views/completion/CompletionQuery.vue | 209 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 209 insertions(+), 0 deletions(-)
diff --git a/emergency-repair-web/src/views/completion/CompletionQuery.vue b/emergency-repair-web/src/views/completion/CompletionQuery.vue
new file mode 100644
index 0000000..38044cf
--- /dev/null
+++ b/emergency-repair-web/src/views/completion/CompletionQuery.vue
@@ -0,0 +1,209 @@
+<template>
+ <div class="page">
+ <div class="page-title">
+ <div>
+ <h2>瀹屽伐淇℃伅鏌ラ槄</h2>
+ <p>鎸夋晠闅滄眹鎬伙紝鍚屼竴鏁呴殰鐨勫寮犳淳宸ュ崟鍏辩敤鏁呴殰淇℃伅锛屽畬宸ュ鐞嗘儏鍐靛拰鏇存崲鍣ㄦ潗鎸夊鏉℃槑缁嗗睍绀�</p>
+ </div>
+ <el-tag type="info">鍏� {{ rows.length }} 涓晠闅�</el-tag>
+ </div>
+
+ <div class="toolbar">
+ <el-input v-model="filters.keyword" placeholder="鏁呴殰缂栧彿 / rk_X鍙� / 娲惧伐鍗曠紪鍙� / 宸ョ▼鍚嶇О / 鎵夸慨鍗曚綅" clearable style="width:380px" @keyup.enter.native="load"></el-input>
+ <el-input v-model="filters.contractorName" placeholder="鎵夸慨鍗曚綅" clearable style="width:190px" @keyup.enter.native="load"></el-input>
+ <el-select v-model="filters.completionStatus" placeholder="瀹屽伐鐘舵��" clearable style="width:140px">
+ <el-option v-for="(meta, key) in completionStatuses" :key="key" :label="meta.text" :value="key"></el-option>
+ </el-select>
+ <el-date-picker v-model="filters.completionDate" type="daterange" value-format="yyyy-MM-dd" range-separator="鑷�" start-placeholder="瀹屽伐寮�濮嬫棩鏈�" end-placeholder="瀹屽伐缁撴潫鏃ユ湡" style="width:270px"></el-date-picker>
+ <el-button type="primary" icon="el-icon-search" v-permission="'completion:query:query'" @click="load">鏌ヨ</el-button>
+ <el-button icon="el-icon-refresh" @click="reset">閲嶇疆</el-button>
+ </div>
+
+ <div class="table-panel">
+ <el-table v-loading="loading" :data="displayRows" border size="small" :span-method="spanMethod" row-key="rowKey">
+ <el-table-column label="搴忓彿" width="62" align="center">
+ <template slot-scope="{ row }">{{ row.faultIndex }}</template>
+ </el-table-column>
+ <el-table-column prop="faultCode" label="鏁呴殰缂栧彿" width="150"></el-table-column>
+ <el-table-column prop="xNo" label="rk_X鍙�" width="72"></el-table-column>
+ <el-table-column prop="equipmentName" label="璁惧鍚嶇О" width="130" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="engineeringNameDesc" label="宸ョ▼鍚嶇О鍙婃崯鍧忔儏鍐�" min-width="190" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="reportUnit" label="涓婃姤鍗曚綅" width="130" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="reportDate" label="涓婃姤鏃ユ湡" width="105"></el-table-column>
+
+ <el-table-column prop="workOrderNo" label="娲惧伐鍗曠紪鍙�" width="155"></el-table-column>
+ <el-table-column prop="contractorName" label="鎵夸慨鍗曚綅" width="150" show-overflow-tooltip></el-table-column>
+ <el-table-column label="瀹屽伐鐘舵��" width="100">
+ <template slot-scope="{ row }">
+ <el-tag size="mini" :type="completionMeta(row.completionStatus).type">{{ completionMeta(row.completionStatus).text }}</el-tag>
+ </template>
+ </el-table-column>
+ <el-table-column prop="engineeringNo" label="宸ョ▼缂栧彿" width="145"></el-table-column>
+ <el-table-column label="寮�宸� / 瀹屽伐" width="190">
+ <template slot-scope="{ row }">{{ formatPeriod(row.startDate, row.finishDate) }}</template>
+ </el-table-column>
+ <el-table-column prop="contractorPerson" label="鎵夸慨浜�" width="100"></el-table-column>
+ <el-table-column label="瀹屽伐澶勭悊鎯呭喌" min-width="260">
+ <template slot-scope="{ row }">
+ <div v-if="row.solutions && row.solutions.length" class="detail-list">
+ <div v-for="(item, index) in row.solutions" :key="index" class="detail-line">
+ <span class="detail-index">{{ index + 1 }}</span>
+ <span>{{ item.content || '-' }}</span>
+ </div>
+ </div>
+ <span v-else class="muted">-</span>
+ </template>
+ </el-table-column>
+ <el-table-column label="鏇存崲鍣ㄦ潗" min-width="300">
+ <template slot-scope="{ row }">
+ <div v-if="row.materials && row.materials.length" class="detail-list">
+ <div v-for="(item, index) in row.materials" :key="index" class="material-line">
+ <span class="detail-index">{{ index + 1 }}</span>
+ <div>
+ <div><strong>{{ item.name || '-' }}</strong><span v-if="item.specification"> / {{ item.specification }}</span><span v-if="item.quantity != null"> 脳 {{ item.quantity }}{{ item.unit || '' }}</span></div>
+ <div class="material-meta">{{ materialMeta(item) }}</div>
+ </div>
+ </div>
+ </div>
+ <span v-else class="muted">-</span>
+ </template>
+ </el-table-column>
+ <el-table-column prop="qualityInfo" label="淇悗璐ㄩ噺鎯呭喌" min-width="180" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="reasonAnalysis" label="鍘熷洜鍒嗘瀽" min-width="180" show-overflow-tooltip></el-table-column>
+ <el-table-column prop="submitTime" label="鎻愪氦鏃堕棿" width="160"></el-table-column>
+ </el-table>
+ </div>
+ </div>
+</template>
+
+<script>
+import api from '@/api'
+import { completionStatuses, statusMeta } from '@/utils/dict'
+
+export default {
+ name: 'CompletionQuery',
+ data() {
+ return {
+ loading: false,
+ completionStatuses,
+ rows: [],
+ filters: {
+ keyword: '',
+ contractorName: '',
+ completionStatus: '',
+ completionDate: []
+ }
+ }
+ },
+ computed: {
+ displayRows() {
+ const rows = []
+ this.rows.forEach((fault, faultIndex) => {
+ const workOrders = fault.workOrders || []
+ const total = workOrders.length || 1
+ if (!workOrders.length) {
+ rows.push({ ...fault, faultIndex: faultIndex + 1, faultRowspan: 1, rowKey: fault.faultId + '-empty' })
+ return
+ }
+ workOrders.forEach((workOrder, index) => {
+ rows.push({
+ ...fault,
+ ...workOrder,
+ faultIndex: faultIndex + 1,
+ faultRowspan: index === 0 ? total : 0,
+ rowKey: fault.faultId + '-' + workOrder.workOrderId
+ })
+ })
+ })
+ return rows
+ }
+ },
+ created() {
+ this.load()
+ },
+ methods: {
+ load() {
+ this.loading = true
+ const range = this.filters.completionDate || []
+ api.get('/work-orders/completion/query', {
+ params: {
+ keyword: this.filters.keyword || undefined,
+ contractorName: this.filters.contractorName || undefined,
+ completionStatus: this.filters.completionStatus || undefined,
+ startDate: range[0] || undefined,
+ endDate: range[1] || undefined
+ }
+ }).then(res => {
+ this.rows = res.data || []
+ }).finally(() => {
+ this.loading = false
+ })
+ },
+ reset() {
+ this.filters = { keyword: '', contractorName: '', completionStatus: '', completionDate: [] }
+ this.load()
+ },
+ completionMeta(value) {
+ return statusMeta(completionStatuses, value)
+ },
+ spanMethod({ row, columnIndex }) {
+ if (columnIndex <= 6) {
+ return row.faultRowspan === 0 ? { rowspan: 0, colspan: 0 } : { rowspan: row.faultRowspan, colspan: 1 }
+ }
+ return { rowspan: 1, colspan: 1 }
+ },
+ formatPeriod(startDate, finishDate) {
+ return [startDate || '-', finishDate || '-'].join(' 鑷� ')
+ },
+ materialMeta(item) {
+ const parts = []
+ if (item.technicalParameter) parts.push(item.technicalParameter)
+ if (item.source) parts.push('鏉ユ簮锛�' + item.source)
+ if (item.outboundNo) parts.push('鍑哄簱鍗曪細' + item.outboundNo)
+ if (item.certificate) parts.push('鍚堟牸璇佹槑锛�' + item.certificate)
+ if (item.remark) parts.push('澶囨敞锛�' + item.remark)
+ return parts.join('锛�') || '-'
+ }
+ }
+}
+</script>
+
+<style scoped>
+.table-panel {
+ overflow-x: auto;
+}
+.detail-list {
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+}
+.detail-line,
+.material-line {
+ display: flex;
+ align-items: flex-start;
+ gap: 6px;
+ line-height: 20px;
+}
+.material-line > div {
+ min-width: 0;
+}
+.detail-index {
+ flex: 0 0 auto;
+ min-width: 16px;
+ height: 16px;
+ margin-top: 2px;
+ border-radius: 50%;
+ color: #fff;
+ background: #7b8fa6;
+ font-size: 11px;
+ line-height: 16px;
+ text-align: center;
+}
+.material-meta {
+ color: #7b8a9a;
+ font-size: 12px;
+}
+.muted {
+ color: #a3afbc;
+}
+</style>
--
Gitblit v1.9.1