534 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!--
* @Author: SunTao 328867980@qq.com
* @Date: 2025-02-10 13:46:51
* @LastEditors: SunTao 328867980@qq.com
* @LastEditTime: 2025-02-27 10:27:02
* @FilePath: \znxjxt-ui\src\views\xj\document\maintenance-notice\components\disease-dialog.vue
* @Description: 生成通知单-新增弹窗-选择病害
-->
<template>
<div class="content">
<!-- 列表查询条件 -->
<el-form ref="diseaseQueryForm" :model="diseaseForm" :rules="diseaseFormRules" size="small" :inline="true"
label-width="100px">
<el-form-item label="道路名称" prop="segmentId">
<el-select v-model="diseaseForm.segmentId" placeholder="请选择路段" filterable clearable>
<el-option v-for="item in segmentList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="采集时间" prop="dateTime">
<el-date-picker v-model="dateTime" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期"
format="yyyy-MM-dd" value-format="yyyy-MM-dd" clearable />
</el-form-item>
<el-form-item label="病害类型" prop="paramsDefectType">
<el-cascader v-model="paramsDefectType" :options="tableDefect" :props="{
checkStrictly: true,
emitPath: true,
children: 'subTypes',
}" clearable></el-cascader>
</el-form-item>
<el-form-item label="上下行" prop="inspectDirection">
<el-select v-model="diseaseForm.inspectDirection" placeholder="请选择" clearable>
<el-option label="上行" value="0" />
<el-option label="下行" value="1" />
</el-select>
</el-form-item>
<el-form-item label="公里桩" prop="stakeRange">
<el-input v-model="diseaseForm.stakeStart" placeholder="起始公里桩" style="width: 10rem" clearable />
<span style="margin: 0 5px">-</span>
<el-input v-model="diseaseForm.stakeEnd" placeholder="终止公里桩" style="width: 10rem" clearable />
<el-tooltip class="item" effect="dark" content="格式为K0000+000" placement="top">
<i class="el-icon-info"></i>
</el-tooltip>
</el-form-item>
<el-form-item label="病害id" prop="id">
<el-input v-model="diseaseForm.id" placeholder="请填写病害id" clearable />
</el-form-item>
<el-form-item label="病害长度" prop="lengthRange">
<el-input-number v-model="diseaseForm.minLen" controls-position="right" placeholder="最小长度"
:min="0"></el-input-number>
<span style="margin: 0 5px">-</span>
<el-input-number v-model="diseaseForm.maxLen" controls-position="right" placeholder="最大长度"
:min="0"></el-input-number>
</el-form-item>
<el-form-item label="快照id" prop="snapshotId">
<el-input v-model="diseaseForm.snapshotId" placeholder="请填写快照id" clearable />
</el-form-item>
<el-form-item label="病害面积" prop="areaRange">
<el-input-number v-model="diseaseForm.minArea" controls-position="right" placeholder="最小面积"
:min="0"></el-input-number>
<span style="margin: 0 5px">-</span>
<el-input-number v-model="diseaseForm.maxArea" controls-position="right" placeholder="最大面积"
:min="0"></el-input-number>
</el-form-item>
<el-form-item label="巡检任务" prop="taskId">
<el-select v-model="diseaseForm.taskId" placeholder="请选择巡检任务" filterable clearable>
<el-option v-for="item in taskList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
<el-form-item label="是否已确认" prop="confirmStatus">
<el-select v-model="diseaseForm.confirmStatus" placeholder="请选择" clearable>
<el-option label="确认" value="1" />
<el-option label="未确认" value="2" />
</el-select>
</el-form-item>
<el-form-item>
<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-form-item>
</el-form>
<!-- 列表 -->
<el-table ref="diseaseTable" v-loading="loading" :data="diseaseList" :row-key="getRowKey"
@selection-change="handleSelectionChange" height="33rem" style="width: 100%">
<el-table-column type="selection" :reserve-selection="true" width="55" align="center" />
<el-table-column label="路段名称" align="center" prop="segmentName" />
<el-table-column label="采集时间" align="center" prop="createdTimeLocal">
</el-table-column>
<el-table-column label="病害类型" align="center" prop="defectTypeName">
</el-table-column>
<!-- <el-table-column label="病害状态" align="center" prop="state">
<template slot-scope="scope">
<span>{{ filterState(scope.row.state) }}</span>
</template>
</el-table-column> -->
<el-table-column label="开始桩号" align="center" prop="stakeStart" />
<el-table-column label="结束桩号" align="center" prop="stakeEnd" />
<el-table-column label="病害图片" align="center" prop="media">
<template slot-scope="scope">
<img @click="showScreenImg(scope.row)" height="50" :src="scope.row.mediaUrl" />
</template>
</el-table-column>
<el-table-column label="病害长度" align="center" prop="targetLen">
<template slot-scope="scope">
{{ scope.row.targetLen * 1 <= 0 ? "" : `${scope.row.targetLen}米` }} </template>
</el-table-column>
<el-table-column label="病害面积" align="center" prop="targetArea" />
<el-table-column label="道路方向" align="center" prop="inspectDirection">
<template slot-scope="scope">
<span>{{
scope.row.inspectDirection === "0" ? "上行" : "下行"
}}</span>
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<div class="pagination-part">
<el-pagination background :current-page.sync="pagination.page" @current-change="handleCurrentChange"
:page-sizes="[10, 20, 30, 40]" :page-size.sync="pagination.size" @size-change="handleSizeChange"
layout="total, sizes, prev, pager, next, jumper" :total="tableTotal">
</el-pagination>
</div>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
<!-- 查看图片大图 -->
<el-dialog title="查看图片" :visible.sync="showImageDialog" width="85rem" append-to-body destroy-on-close
@close="imgCancel">
<div class="image-container" ref="imageContainer">
<img :src="currentImageItem.mediaUrl" alt="Main Image" ref="mainImage" @load="updateRects" />
<div v-for="(rect, index) in rects" :key="index" class="rect-overlay" :style="getRectStyle(rect)"></div>
<div class="rect-image">
采集时间:
{{ new Date(currentImageItem.createdTime).toLocaleString() }}
起始桩号 {{ currentImageItem.stakeStart || "暂无数据" }} 终止桩号
{{ currentImageItem.stakeEnd || "暂无数据" }}
病害类型
{{ currentImageItem.defectTypeName || "暂无数据" }}
病害面积{{ currentImageItem.targetArea }}平方米 病害长度{{
currentImageItem.targetLen * 1 <= 0 ? "暂无数据" : `${currentImageItem.targetLen}` }} </div>
</div>
</el-dialog>
</div>
</template>
<script>
import { getMaintenanceNoticeList, } from "@/api/xj/document";
export default {
name: "DiseaseDialog",
props: {
segmentList: {
type: Array,
default: () => [],
},
// 病害类型下拉
tableDefect: {
type: Array,
default: () => []
},
checkedDiseaseList: {
type: Array,
default: () => []
}
},
data() {
return {
// 传接口查询条件
searchForm: {},
// 病害列表查询条件
diseaseForm: {
segmentId: "",
defectType: "",
classType: "",
taskId: "",
state: "",
inspectDirection: "",
stakeStart: "",
stakeEnd: "",
warningFlag: null,
minLen: undefined,
maxLen: undefined,
minArea: undefined,
maxArea: undefined,
confirmStatus: "",
id: "",
snapshotId: "",
taskId: "",
},
// 表单校验
diseaseFormRules: {
stakeRange: [{ required: false, message: "请输入桩号", trigger: "blur" }, {
trigger: 'blur',
validator: (rules, value, callback) => {
const start = this.diseaseForm.stakeStart;
const end = this.diseaseForm.stakeEnd;
if (start) {
const phonereg = /^K\d{4}\+\d{3}$/;
if (!phonereg.test(start)) {
callback(new Error("请按照K0000+000格式进行填写"))
} else {
callback()
}
} else if (end) {
const phonereg = /^K\d{4}\+\d{3}$/;
if (!phonereg.test(end)) {
callback(new Error("请按照K0000+000格式进行填写"))
} else {
callback()
}
} else {
callback()
}
},
}]
},
// 采集时间绑定
dateTime: [],
// 病害类型级联下拉绑定
paramsDefectType: [],
// 巡检任务下拉数据
taskList: [],
// 病害列表数据
diseaseList: [],
// 列表加载状态
loading: false,
// 列表选中数据
checkList: [],
// 分页-列表总数
tableTotal: 0,
// 分页-页数页码
pagination: {
page: 1,
size: 10,
},
// 查看图片大图弹窗显隐控制
showImageDialog: false,
// 查看大图片路径
currentImageItem: {},
// 图片病害位置信息
rects: [],
}
},
mounted() {
this.getDiseaseList();
},
methods: {
/**
* @description: 点击查询事件
* @param {*}
* @return {*}
*/
handleQuery() {
this.$refs["diseaseQueryForm"].validate((valid) => {
if (valid) {
this.diseaseForm.classType = this.paramsDefectType
? this.paramsDefectType[0]
: "";
this.diseaseForm.defectType = this.paramsDefectType
? this.paramsDefectType.length > 1
? this.paramsDefectType[1]
: ""
: "";
this.searchForm = JSON.parse(JSON.stringify(this.diseaseForm));
this.pagination.page = 1;
this.getDiseaseList();
}
});
},
resetQuery() {
this.searchForm = {};
this.diseaseForm = {
segmentId: "",
defectType: "",
classType: "",
taskId: "",
state: "",
inspectDirection: "",
stakeStart: "",
stakeEnd: "",
warningFlag: null,
minLen: undefined,
maxLen: undefined,
minArea: undefined,
maxArea: undefined,
confirmStatus: "",
id: "",
snapshotId: "",
taskId: "",
};
this.paramsDefectType = [];
this.dateTime = [];
this.getDiseaseList();
},
/**
* @description: 获取病害列表数据
* @param {*}
* @return {*}
*/
getDiseaseList() {
this.loading = true;
const params = {
...this.searchForm,
...this.pagination,
startTime: this.dateTime ? this.dateTime[0] : "",
endTime: this.dateTime ? this.dateTime[1] : "",
maintenanceStatus: "未生成",
};
getMaintenanceNoticeList(params)
.then(({ code, data }) => {
if (code === 200) {
// 切换列表选中状态
this.diseaseList = data.table.rows;
this.tableTotal = data.table.total;
// 使用 Set 提高查找效率
const checkedIds = new Set(this.checkedDiseaseList.map(item => item.id));
// 设置表格选中状态
this.$nextTick(() => {
this.diseaseList.forEach((item) => {
if (checkedIds.has(item.id)) {
this.$refs.diseaseTable.toggleRowSelection(item, true);
}
});
});
this.loading = false;
}
})
.catch(() => {
this.loading = false;
});
},
/**
* @description: 列表行绑定id
* @param {*} row
* @return {*}
*/
getRowKey(row) {
return row.id;
},
/**
* @description: 列表选择改变事件
* @param {*} selection
* @return {*}
*/
handleSelectionChange(selection) {
this.checkList = selection;
},
/**
* @description: 切换分页
* @param {*} arg
* @return {*}
*/
handleCurrentChange(arg) {
this.pagination.page = arg;
this.getDiseaseList();
// 切换列表选中状态
this.checkedDiseaseList.forEach((item) => {
this.$refs.diseaseTable.toggleRowSelection(item);
})
},
/**
* @description: 切换每条/页
* @param {*} arg
* @return {*}
*/
handleSizeChange(arg) {
this.pagination.size = arg;
this.getDiseaseList();
// 切换列表选中状态
this.checkedDiseaseList.forEach((item) => {
this.$refs.diseaseTable.toggleRowSelection(item);
})
},
/**
* @description: 点击取消事件
* @param {*} arg
* @return {*}
*/
cancel() {
this.$emit("cancel");
},
/**
* @description: 点击确定事件
* @param {*} arg
* @return {*}
*/
submitForm() {
this.$emit("checkedList", this.checkList);
},
/**
* @description: 打开查看图片弹窗
* @param {*} item
* @return {*}
*/
showScreenImg(item) {
this.currentImageItem = item;
this.showImageDialog = true;
},
/**
* @description: 图片位置信息获取
* @param {*} val
* @return {*}
*/
updateRects() {
this.rects = [];
this.rectsItem = {};
const rects = this.currentImageItem?.rect?.split(",").map(Number) || [];
this.rects = [
{
left: rects[0],
top: rects[1],
width: rects[2],
height: rects[3],
},
];
},
/**
* @description: 图片红框位置
* @param {*} left
* @param {*} top
* @param {*} width
* @param {*} height
* @return {*}
*/
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",
};
},
/**
* @description: 关闭查看图片弹窗
* @param {*} val
* @return {*}
*/
imgCancel() {
this.showImageDialog = false;
this.currentImageItem = {};
this.rects = [];
},
}
}
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
}
/* 分页样式 */
.pagination-part {
width: 100%;
display: flex;
padding-top: 1rem;
justify-content: flex-end;
}
/* 页脚 */
.dialog-footer {
padding: 1rem 0;
display: flex;
justify-content: flex-end;
}
/* 查看大图弹窗 */
.image-container {
position: relative;
width: 100%;
height: 80%;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.image-container img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.rect-overlay {
position: absolute;
pointer-events: none;
border: 2px solid red;
}
// 图片信息
.rect-image {
width: 90%;
position: absolute;
top: 0;
font-size: 1.2rem;
color: #ffffff;
background-color: rgba(0, 0, 0, 0.5);
}
</style>