519 lines
14 KiB
Vue
Raw Normal View History

2024-11-04 10:38:06 +08:00
<!--
* @Author: SunTao 328867980@qq.com
* @Date: 2024-11-01 17:25:06
* @LastEditors: SunTao 328867980@qq.com
* @LastEditTime: 2024-11-04 10:30:58
* @FilePath: \znxjxt-ui\src\views\xj\inspection\confirmation-management\image-dialog.vue
* @Description: 病害确认-影像模式弹窗
-->
<template>
<div class="content">
<div class="image-content">
<!-- 图片展示 -->
<div class="sidebar" ref="sidebar" @scroll="handleScroll">
<img
v-for="(item, index) in defectData"
:key="item.id"
:src="item.media[0].img"
:alt="'Image ' + (index + 1)"
@click="showImage(index)"
:class="{ selected: currentIndex === index }"
/>
</div>
<!-- 右侧区域 -->
<div class="main-content">
<div class="image-form">
<el-form
:model="imgForm"
ref="imgForm"
size="small"
:inline="true"
label-width="5rem"
>
<el-row :gutter="24">
<el-col :span="7">
<el-form-item label="路段名称">
<el-select
v-model="imgForm.segmentId"
placeholder="请选择路段名称"
:style="{ width: '10rem' }"
clearable
>
<el-option
v-for="item in roadTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="病害类型">
<el-select
v-model="imgForm.defectType"
placeholder="请选择路段名称"
:style="{ width: '10rem' }"
clearable
>
<el-option
v-for="item in defectTypeList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="公里桩">
<el-input
v-model="imgForm.stakeStart"
placeholder="起始公里桩"
style="width: 7rem"
clearable
/>
<span style="margin: 0 5px">-</span>
<el-input
v-model="imgForm.stakeEnd"
placeholder="终止公里桩"
style="width: 7rem"
clearable
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="6">
<el-button
type="primary"
icon="el-icon-search"
size="mini"
@click="handleQuery"
>搜索</el-button
>
<el-button
icon="el-icon-refresh"
size="mini"
@click="resetQuery"
>重置</el-button
>
</el-col>
</el-row>
</el-form>
</div>
<div class="image-view">
<div class="view-content">
<img
src="currentImage"
alt="Main Image"
ref="mainImage"
@load="updateRects"
/>
<div
v-for="(rect, index) in rects"
:key="index"
class="rect-overlay"
:style="getRectStyle(rect)"
></div>
</div>
<div class="view-info">
采集时间: {{ new Date(rectsItem.createdTime).toLocaleString()
}}<br />
起始桩号: {{ rectsItem.stakeStart || "暂无数据" }} 终止桩号:
{{ rectsItem.stakeEnd || "暂无数据" }}<br />
路产状态: {{ filterState(rectsItem.state) }}
</div>
</div>
<div class="image-bottom">
<img
v-for="(mediaItem, index) in currentThumbnails"
:key="'thumb-' + index"
:src="mediaItem.img"
:alt="'Thumb ' + (index + 1)"
@click="showThumbnailImage(index)"
:class="{ selected: selectedThumbnail === index }"
/>
</div>
</div>
</div>
<div class="footer">
<el-button type="success" size="mini" @click="changeDefect('1')"
>是病害(Y)</el-button
>
<el-button type="warning" size="mini" @click="changeDefect('2')"
>不是病害(N)</el-button
>
</div>
</div>
</template>
<script>
import { getDefectStatus } from "@/api/xj/disease";
import { defeaseList, getSegment, getItemTypes } from "@/api/xj/screen/index";
export default {
name: "ImageDialog",
props: {},
data() {
return {
// 左侧图片数据
defectData: [],
// 表单绑定
imgForm: {
// 路段名称
segmentId: "",
// 病害类型
defectType: "",
},
// 路段下拉数据
roadTypeList: [],
// 病害类型下拉数据
defectTypeList: [],
// 病害状态下拉选项
defectStatus: [],
// 分页绑定
params: {
page: 1,
size: 10,
},
// 图片病害位置信息
rects: [],
// 图片下方数据
rectsItem: {},
};
},
computed: {
currentImage() {
const thumbnails = this.currentThumbnails;
return (
thumbnails[this.selectedThumbnail]?.img || thumbnails[0]?.img || ""
);
},
currentThumbnails() {
return this.defectData[this.currentIndex]?.media || [];
},
},
created() {
this.getSegmentList();
this.getDefectType();
this.getDefectStatusList();
},
mounted() {
this.getList();
this.showImage(0);
window.addEventListener("keydown", this.handleKeydown);
window.addEventListener("resize", this.updateRects);
},
methods: {
/* 获取路段下拉数据 */
getSegmentList() {
getSegment().then(({ code, data }) => {
if (code === 200) {
this.roadTypeList = data;
}
});
},
/* 获取病害类型下拉数据 */
getDefectType() {
getItemTypes({ type: "defect" }).then(({ code, data }) => {
if (code === 200) {
this.defectTypeList = data;
}
});
},
/* 查询病害状态下拉数据 */
getDefectStatusList() {
getDefectStatus().then(({ data, code }) => {
if (code === 200) {
this.defectStatus = data;
}
});
},
/* 过滤列表病害状态 */
filterState(value) {
let a = null;
[a] = this.defectStatus.filter((item) => {
return item.value === value;
});
if (a) {
return a.label;
}
},
/* 获取左侧图片列表 */
getList() {
this.loading = true;
const data = {
...this.imgForm,
...this.params,
};
defeaseList(data)
.then((response) => {
this.defectData.push(...response.data);
this.loading = false;
})
.catch(() => {
this.loading = false;
});
},
/* 点击搜索事件 */
handleQuery() {
const stakeReg = /^K\d{4}\+\d{3}$/;
if (this.imgForm.stakeStart) {
if (stakeReg.test(this.imgForm.stakeStart)) {
this.defectData = [];
this.params = {
page: 1,
size: 10,
};
this.getList();
this.showImage(0);
} else {
this.$modal.msgWarning("请按照'K0000+000'格式填写公里桩进行修改");
}
} else if (this.imgForm.stakeEnd) {
if (stakeReg.test(this.imgForm.stakeEnd)) {
this.defectData = [];
this.params = {
page: 1,
size: 10,
};
this.getList();
this.showImage(0);
} else {
this.$modal.msgWarning("请按照'K0000+000'格式填写公里桩进行修改");
}
} else {
this.defectData = [];
this.params = {
page: 1,
size: 10,
};
this.getList();
this.showImage(0);
}
},
/* 重置事件 */
resetQuery() {
this.defectData = [];
this.imgForm = {
segmentId: "",
defectType: "",
stakeStart: "",
stakeEnd: "",
};
this.params = {
page: 1,
size: 10,
};
this.getList();
this.showImage(0);
},
/* 左侧点击图片事件 */
showImage(index) {
this.currentIndex = index;
this.selectedThumbnail = 0; // Reset to the first thumbnail when changing the main item
this.scrollToCurrentImage();
this.$nextTick(() => {
this.updateRects();
});
},
scrollToCurrentImage() {
const sidebarImages = this.$refs.sidebar.querySelectorAll("img");
const currentImageElement = sidebarImages[this.currentIndex];
if (currentImageElement) {
currentImageElement.scrollIntoView({
behavior: "smooth",
block: "nearest",
});
}
},
/* 图片位置信息获取 */
updateRects() {
this.rects = [];
this.rectsItem = {};
if (this.defectData.length > 0) {
const image = this.$refs.mainImage;
const rects =
this.defectData[this.currentIndex]?.media[
this.selectedThumbnail
]?.rect
?.split(",")
.map(Number) || [];
this.rects = [
{
left: rects[0],
top: rects[1],
width: rects[2],
height: rects[3],
},
];
this.rectsItem = this.defectData[this.currentIndex];
}
},
/* 图片红框位置 */
getRectStyle({ left, top, width, height }) {
const image = this.$refs.mainImage;
const container = this.$refs.imageContainer;
if (!image || !container) return {};
const scaleX = container.clientWidth / image.naturalWidth;
const scaleY = container.clientHeight / image.naturalHeight;
const scale = Math.min(scaleX, scaleY);
const renderedWidth = image.naturalWidth * scale;
const renderedHeight = image.naturalHeight * scale;
const offsetX = (container.clientWidth - renderedWidth) / 2;
const offsetY = (container.clientHeight - renderedHeight) / 2;
return {
position: "absolute",
left: `${left * scale + offsetX}px`,
top: `${top * scale + offsetY}px`,
width: `${width * scale}px`,
height: `${height * scale}px`,
border: "2px solid #FF0000",
boxSizing: "border-box",
};
},
/* 滚动触发事件 */
handleScroll() {
// 滚动高度+容器高度 滚动区域高度
const sidebar = this.$refs.sidebar;
if (
sidebar.scrollTop + sidebar.clientHeight >= sidebar.scrollHeight - 1 &&
!this.loading
) {
this.loadMoreImages();
}
},
/* 加载更多图片方法 */
loadMoreImages() {
this.params.size += 10;
this.getList();
},
/* 是病害/不是病害点击事件 */
changeDefect(value) {},
/* 键盘事件 */
handleKeydown(event) {
console.log(event.keyCode, "fff");
if (event.key === "ArrowUp") {
if (this.currentIndex > 0) {
this.currentIndex--;
this.selectedThumbnail = 0; // Reset when changing main images via keyboard
this.scrollToCurrentImage();
this.updateRects();
}
} else if (event.key === "ArrowDown") {
if (this.currentIndex <= this.defectData.length - 1) {
this.currentIndex === this.defectData.length - 1
? this.currentIndex
: this.currentIndex++;
this.selectedThumbnail = 0; // Reset when changing main images via keyboard
this.scrollToCurrentImage();
this.updateRects();
} else {
this.loadMoreImages();
}
} else if (event.keyCode === 89) {
// 确认病害
this.changeDefect("1");
} else if (event.keyCode === 78) {
// 不是病害
this.changeDefect("2");
}
},
},
beforeDestroy() {
window.removeEventListener("keydown", this.handleKeydown);
window.removeEventListener("resize", this.updateRects);
},
};
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 45rem;
}
.image-content {
width: 100%;
height: 95%;
display: flex;
flex-direction: row;
.sidebar {
width: 20rem;
padding: 10px;
overflow-y: auto;
}
.main-content {
width: calc(100% - 20rem);
padding: 10px;
display: flex;
flex-direction: column;
}
}
// form表单
.image-form {
height: 15%;
width: 100%;
background-color: aqua;
}
// 图片大图预览
.image-view {
height: 70%;
width: 100%;
background-color: aquamarine;
.view-content {
width: 100%;
height: 80%;
}
.view-info {
width: 100%;
height: 20%;
display: flex;
justify-content: center;
}
}
// 图片小图预览
.image-bottom {
width: 100%;
height: 15%;
display: flex;
justify-content: center;
overflow-x: auto;
padding: 10px;
gap: 10px;
background-color: beige;
img {
width: 7rem;
height: 4rem;
cursor: pointer;
border-radius: 3px;
transition: transform 0.2s, border 0.2s;
box-sizing: border-box;
}
img.selected {
border: 3px solid #00aaff;
}
}
.footer {
width: 100%;
height: 5%;
display: flex;
justify-content: flex-end;
}
</style>