You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

702 lines
19 KiB

<template>
<CardBox
class="card-page report-bg"
:showTitle="false"
>
<div class="report-toolbar">
<el-button
class="report-back-btn"
type="primary"
icon="el-icon-back"
size="mini"
@click="backPage"
>返回</el-button>
</div>
<el-table
class="report-table"
border
:data="pointInfo.headerInfoList"
:show-header="false"
:span-method="headerSpan"
>
<el-table-column prop="title1" label="">
<template slot-scope="scope">
<span class="header-title">{{ scope.row.title1 }}</span>
</template>
</el-table-column>
<el-table-column prop="info1" label=""> </el-table-column>
<el-table-column prop="title2" label="">
<template slot-scope="scope">
<span class="header-title">{{ scope.row.title2 }}</span>
</template>
</el-table-column>
<el-table-column prop="info2" label=""> </el-table-column>
</el-table>
<!-- 缺陷点位汇总 - 按任务分组 -->
<div
style="margin-top: 10px"
v-if="
pointInfo.errorPointsByTask &&
Object.keys(pointInfo.errorPointsByTask).length > 0
"
>
<div class="point-info-title">缺陷结果数量汇总</div>
<div
v-for="(taskPoints, taskName) in pointInfo.errorPointsByTask"
:key="'error_' + taskName"
class="task-group"
>
<div
class="task-group-title"
v-if="shouldShowTaskName(taskName, 'error')"
>
任务名称:{{ taskName }}
</div>
<el-table class="report-table" border stripe :data="getPaginatedData('error', taskName)">
<el-table-column
prop="code"
label="编号"
align="center"
width="80"
></el-table-column>
<el-table-column
prop="area"
label="区域"
align="center"
></el-table-column>
<el-table-column
prop="pointName"
label="点位"
align="center"
></el-table-column>
<el-table-column
prop="inspectionResults"
label="巡视结果"
align="center"
></el-table-column>
<el-table-column prop="inspectionImg" label="巡视图像" align="center">
<template slot-scope="scope">
<div class="inspection-img-wrap">
<!-- 直接使用原来的 inspectionImg,让 AsyncImage 自己处理 -->
<AsyncImage
class="inspection-img"
fit="contain"
:src="scope.row.inspectionImg"
@click="lookImageDetail(scope.row.inspectionImg)"
></AsyncImage>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div
class="pagination-wrap"
v-if="getTotalCount('error', taskName) > pageSize"
>
<el-pagination
background
small
layout="total, prev, pager, next"
:total="getTotalCount('error', taskName)"
:page-size="pageSize"
:current-page.sync="currentPageMap[`error_${taskName}`]"
@current-change="() => $forceUpdate()"
>
</el-pagination>
</div>
</div>
</div>
<!-- 正常点位汇总 - 按任务分组 -->
<div
style="margin-top: 10px"
v-if="
pointInfo.normalPointsByTask &&
Object.keys(pointInfo.normalPointsByTask).length > 0
"
>
<div class="point-info-title">正常结果数量汇总</div>
<div
v-for="(taskPoints, taskName) in pointInfo.normalPointsByTask"
:key="'normal_' + taskName"
class="task-group"
>
<div
class="task-group-title"
v-if="shouldShowTaskName(taskName, 'normal')"
>
任务名称:{{ taskName }}
</div>
<el-table class="report-table" border stripe :data="getPaginatedData('normal', taskName)">
<el-table-column
prop="code"
label="编号"
align="center"
width="80"
></el-table-column>
<el-table-column
prop="area"
label="区域"
align="center"
></el-table-column>
<el-table-column
prop="pointName"
label="点位"
align="center"
></el-table-column>
<el-table-column
prop="inspectionResults"
label="巡视结果"
align="center"
></el-table-column>
<el-table-column prop="inspectionImg" label="巡视图像" align="center">
<template slot-scope="scope">
<div class="inspection-img-wrap">
<!-- 直接使用原来的 inspectionImg AsyncImage 自己处理 -->
<AsyncImage
class="inspection-img"
fit="contain"
:src="scope.row.inspectionImg"
@click="lookImageDetail(scope.row.inspectionImg)"
></AsyncImage>
</div>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div
class="pagination-wrap"
v-if="getTotalCount('normal', taskName) > pageSize"
>
<el-pagination
background
small
layout="total, prev, pager, next"
:total="getTotalCount('normal', taskName)"
:page-size="pageSize"
:current-page.sync="currentPageMap[`normal_${taskName}`]"
@current-change="() => $forceUpdate()"
>
</el-pagination>
</div>
</div>
</div>
<el-dialog
title="图片预览"
:visible.sync="showPreviewImages"
:close-on-click-modal="false"
:close-on-press-escape="false"
:destroy-on-close="true"
custom-class="card-dialog card-page"
width="70%"
append-to-body
>
<ImagePreview
v-if="showPreviewImages"
:imageUrls="showImgesUrls"
:selectImgPosition="previewImagePos"
:showTemperatureTool="false"
/>
</el-dialog>
</CardBox>
</template>
<script>
import ImagePreview from "@/views/cards/components/ImagePreview/index.vue";
import AsyncImage from "@/components/AsyncImage/index.vue";
import { getPatrolReportShaoxing } from "@/api/inspectionDataManage/inspectionReporter";
import CardBox from "../components/cardBox.vue";
export default {
name: "PatrolReportDetail",
components: { AsyncImage, ImagePreview, CardBox },
data() {
return {
lineId: null,
reportType: 0,
showPreviewImages: false,
showImgesUrls: [],
previewImagePos: 0,
reportInfo: {},
pointInfo: {},
code: "",
returnState: {},
urlFrom: "",
// 分页配置
pageSize: 20,
currentPageMap: {},
// 原始数据缓存
originalDataCache: {
error: {},
normal: {},
},
};
},
created() {
this.lineId = this.$route.query.lineId;
this.urlFrom =
this.$route.query.fromComponent || this.$route.query.fromPage;
this.reportType =
this.$route.query.reportType ?? this.$route.query.filter;
if (!this.lineId) {
this.lineId = JSON.parse(sessionStorage.getItem("reportLineId"));
}
if (
this.reportType === undefined ||
this.reportType === null ||
this.reportType === ""
) {
const savedReportType = sessionStorage.getItem("reportType");
this.reportType = savedReportType ? JSON.parse(savedReportType) : 0;
}
this.getDetail();
if (
this.urlFrom === "InspectionTask" ||
this.urlFrom === "inspectionTask"
) {
const savedState = sessionStorage.getItem("inspectionTaskState");
if (savedState) {
console.log("已保存巡检任务页面状态返回时会自动恢复");
}
}
},
methods: {
getDetail() {
if (!this.lineId) {
return;
}
let url = "";
if (this.urlFrom == "InspectionTask") {
url = `taskStatus`;
} else {
url = `report`;
}
getPatrolReportShaoxing(url, this.lineId, this.reportType || 0).then((res) => {
// Some deployments return detail as a JSON string; normalize it before grouping.
const report = res && res.data ? res.data : res;
if (report && typeof report.detail === "string") {
try {
report.detail = JSON.parse(report.detail);
} catch (error) {
console.warn("巡视报告详情解析失败", error);
}
}
this.reportInfo = report || {};
this.pointInfo = this.getPointInfo();
this.code = res.code;
// 初始化分页
this.initPagination();
}).catch((error) => {
this.reportInfo = {};
this.pointInfo = {};
console.error("获取巡视报告详情失败", error);
this.$modal && this.$modal.msgError("巡视报告详情加载失败");
});
},
getPointInfo() {
const headerInfoList = [
{
title1: "换流站",
info1: this.reportInfo.stationName,
title2: "",
info2: "",
},
{
title1: "审核人",
info1: this.reportInfo.checkPerson,
title2: "审核时间",
info2: this.reportInfo.checkTime,
},
{
title1: "巡视开始时间",
info1: this.reportInfo.inspectionStartTime,
title2: "巡视结束时间",
info2: this.reportInfo.inspectionEndTime,
},
{
title1: "巡视任务",
info1: this.reportInfo.inspectionTaskName,
title2: "巡视统计",
info2: this.reportInfo.patrolStatistics,
},
{
title1: "巡视结论",
info1: this.reportInfo.description,
title2: "",
info2: "",
},
];
const errorPointsByTask = {};
const normalPointsByTask = {};
if (this.reportInfo.detail) {
// 处理缺陷点位
if (this.reportInfo.detail.缺陷) {
this.reportInfo.detail.缺陷.forEach((taskGroup) => {
Object.keys(taskGroup).forEach((taskName) => {
const points = taskGroup[taskName];
if (points && points.length > 0) {
if (!errorPointsByTask[taskName]) {
errorPointsByTask[taskName] = [];
}
points.forEach((point) => {
if (point.inspectionImg) {
point.inspectionImgList = [point.inspectionImg];
} else {
point.inspectionImgList = [];
}
errorPointsByTask[taskName].push(point);
});
}
});
});
}
// 处理正常点位
if (this.reportInfo.detail.正常) {
this.reportInfo.detail.正常.forEach((taskGroup) => {
Object.keys(taskGroup).forEach((taskName) => {
const points = taskGroup[taskName];
if (points && points.length > 0) {
if (!normalPointsByTask[taskName]) {
normalPointsByTask[taskName] = [];
}
points.forEach((point) => {
if (point.inspectionImg) {
point.inspectionImgList = point.inspectionImg.split(",");
} else {
point.inspectionImgList = [];
}
normalPointsByTask[taskName].push(point);
});
}
});
});
}
} else {
// 兼容旧数据结构
const errorPointsList = [];
const normalPointsList = [];
if (this.reportInfo.info) {
this.reportInfo.info.forEach((element) => {
element.inspectionImgList = [];
if (element.inspectionImg) {
element.inspectionImgList = element.inspectionImg.split(",");
}
if (element.pointStatus == "正常") {
normalPointsList.push(element);
} else if (element.pointStatus == "缺陷") {
errorPointsList.push(element);
}
});
}
const groupByTask = (list) => {
const grouped = {};
list.forEach((item) => {
const taskName = item.taskName || "未分类任务";
if (!grouped[taskName]) {
grouped[taskName] = [];
}
grouped[taskName].push(item);
});
return grouped;
};
Object.assign(errorPointsByTask, groupByTask(errorPointsList));
Object.assign(normalPointsByTask, groupByTask(normalPointsList));
}
// 缓存原始数据用于分页
Object.keys(errorPointsByTask).forEach((taskName) => {
this.originalDataCache.error[taskName] = [
...errorPointsByTask[taskName],
];
});
Object.keys(normalPointsByTask).forEach((taskName) => {
this.originalDataCache.normal[taskName] = [
...normalPointsByTask[taskName],
];
});
return {
headerInfoList,
errorPointsByTask,
normalPointsByTask,
errorPointsList: Object.values(errorPointsByTask).flat(),
normalPointsList: Object.values(normalPointsByTask).flat(),
};
},
initPagination() {
const errorTasks = Object.keys(this.pointInfo.errorPointsByTask || {});
const normalTasks = Object.keys(this.pointInfo.normalPointsByTask || {});
[...errorTasks, ...normalTasks].forEach((task) => {
const type = errorTasks.includes(task) ? "error" : "normal";
const key = `${type}_${task}`;
if (!this.currentPageMap[key]) {
this.currentPageMap[key] = 1;
}
});
},
getTotalCount(type, taskName) {
return this.originalDataCache[type][taskName]?.length || 0;
},
getPaginatedData(type, taskName) {
const key = `${type}_${taskName}`;
const currentPage = this.currentPageMap[key] || 1;
const allData = this.originalDataCache[type][taskName] || [];
const start = (currentPage - 1) * this.pageSize;
const end = start + this.pageSize;
return allData.slice(start, end);
},
shouldShowTaskName(taskName, type) {
let taskCount = 0;
if (type === "error") {
taskCount = Object.keys(this.pointInfo.errorPointsByTask || {}).length;
} else if (type === "normal") {
taskCount = Object.keys(this.pointInfo.normalPointsByTask || {}).length;
}
if (taskCount === 1 && taskName === this.reportInfo.inspectionTaskName) {
return false;
}
return true;
},
handleClose(done) {
this.$emit("update:visible", false);
},
headerSpan({ row, column, rowIndex, columnIndex }) {
if (rowIndex === 0) {
if (columnIndex === 1) {
return [1, 3];
}
}
},
lookImageDetail(imgUrl) {
this.previewImagePos = 0;
this.showImgesUrls = [imgUrl];
this.showPreviewImages = true;
},
backPage() {
const fromComponent =
this.$route.query.fromComponent || this.urlFrom || "inspectionTask";
let targetRoute = {};
if (fromComponent === "InspectionReporter") {
targetRoute = {
name: this.$route.meta.patrolWorkspace
? "InspectionWorkspaceReport"
: "PatrolReport",
};
} else {
targetRoute = {
name: this.$route.meta.patrolWorkspace
? "InspectionWorkspaceTask"
: "InspectionTaskSummary",
};
}
this.$router.replace({
...targetRoute,
query: {
from: "back",
},
});
sessionStorage.removeItem("reportLineId");
sessionStorage.removeItem("reportType");
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .content {
overflow: scroll;
}
::v-deep .el-table__body-wrapper {
max-height: 450px;
overflow-y: scroll;
}
.report-bg {
height: 100%;
overflow: hidden;
}
.report-toolbar {
display: flex;
justify-content: flex-start;
margin-bottom: 12px;
}
.report-back-btn {
border: 1px solid transparent !important;
background:
linear-gradient(#01016b, #01016b) padding-box,
linear-gradient(135deg, #3988ff, #0351c6) border-box !important;
color: #43c0ff !important;
}
.header-title {
font-weight: bold;
}
.point-info-title {
font-size: 20px;
text-align: center;
padding: 10px;
}
.task-group {
margin-top: 20px;
&:first-of-type {
margin-top: 0;
}
.task-group-title {
font-size: 14px;
padding: 8px 0;
margin-bottom: 10px;
}
}
.inspection-img-wrap {
display: flex;
flex-direction: column;
align-items: center;
.inspection-img {
width: 60px;
height: 60px;
cursor: pointer;
}
.inspection-btn {
cursor: pointer;
display: block;
padding-bottom: 20px;
}
}
.pagination-wrap {
margin-top: 15px;
display: flex;
justify-content: flex-end;
}
// 分页组件样式覆盖 - 正常页码白色,当前页蓝色
::v-deep .el-pagination {
.btn-prev,
.btn-next,
.el-pager li {
background-color: transparent;
color: #ffffff;
font-weight: normal;
&:not(.disabled):hover {
color: #40e5f0;
}
}
.el-pager li.active {
color: #40e5f0;
background-color: transparent;
cursor: default;
&:hover {
color: #40e5f0;
}
}
.el-pager li.disabled,
.btn-prev.disabled,
.btn-next.disabled {
color: #7f8c9a;
}
}
::v-deep .el-table {
width: 100% !important;
background: #edf4ff !important;
color: #17345f;
border-color: #6f9ed8 !important;
}
::v-deep .el-table::before,
::v-deep .el-table::after,
::v-deep .el-table--border::after,
::v-deep .el-table--group::after {
background-color: #6f9ed8 !important;
}
::v-deep .el-table__header-wrapper,
::v-deep .el-table__body-wrapper,
::v-deep .el-table__empty-block {
background: transparent !important;
background-color: transparent !important;
}
::v-deep .el-table th.el-table__cell {
background: #0b3d89 !important;
border-color: #6f9ed8 !important;
}
::v-deep .el-table th.el-table__cell .cell {
color: #ffffff !important;
}
::v-deep .el-table td.el-table__cell {
background: #edf4ff !important;
border-color: #a9c4e8 !important;
color: #17345f !important;
}
::v-deep .el-table td.el-table__cell .cell {
color: #17345f !important;
}
.card-page.report-bg ::v-deep .el-table__body .el-table__row,
.card-page.report-bg ::v-deep .el-table__body .el-table__row td.el-table__cell {
background: #edf4ff !important;
}
.card-page.report-bg ::v-deep .el-table__body .el-table__row--striped,
.card-page.report-bg ::v-deep .el-table__body .el-table__row--striped td.el-table__cell {
background: #dce9fa !important;
}
.card-page.report-bg ::v-deep .el-table__body tr:hover > td.el-table__cell {
background: #c8dcf5 !important;
}
::v-deep .el-table__body-wrapper,
::v-deep .content {
scrollbar-width: none;
-ms-overflow-style: none;
}
::v-deep .el-table__body-wrapper::-webkit-scrollbar,
::v-deep .content::-webkit-scrollbar {
width: 0;
height: 0;
display: none;
}
</style>