2025-02-11 17:21:34 +08:00

604 lines
18 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: 2024-11-20 11:58:33
* @LastEditors: SunTao 328867980@qq.com
* @LastEditTime: 2025-02-11 17:12:32
* @FilePath: \znxjxt-ui\src\views\xj\document\maintenance-notice\index.vue
* @Description: 养护通知单
-->
<template>
<div class="content">
<el-form :model="noticeForm" :rules="noticeFormRules" ref="noticeForm" size="small" :inline="true"
label-width="5rem">
<el-form-item label="道路名称" prop="segmentId">
<el-select v-model="noticeForm.segmentId" placeholder="请选择路段" clearable filterable>
<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="noticeForm.inspectDirection" placeholder="请选择" clearable>
<el-option label="上行" value="0" />
<el-option label="下行" value="1" />
</el-select>
</el-form-item>
<el-form-item label="是否紧急" prop="urgentFlag">
<el-select v-model="noticeForm.urgentFlag" placeholder="请选择" clearable>
<el-option label="紧急" value="1" />
<el-option label="不紧急" value="2" />
</el-select>
</el-form-item>
<el-form-item label="公里桩" prop="stakeRange">
<el-input v-model="noticeForm.stakeStart" placeholder="起始公里桩" style="width: 10rem" clearable />
<span style="margin: 0 5px">-</span>
<el-input v-model="noticeForm.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="病害长度" prop="lengthRange">
<el-input-number v-model="noticeForm.minLen" controls-position="right" placeholder="最小长度"
:min="0"></el-input-number>
<span style="margin: 0 5px">-</span>
<el-input-number v-model="noticeForm.maxLen" controls-position="right" placeholder="最大长度"
:min="0"></el-input-number>
</el-form-item>
<el-form-item label="病害面积" prop="areaRange">
<el-input-number v-model="noticeForm.minArea" controls-position="right" placeholder="最小面积"
:min="0"></el-input-number>
<span style="margin: 0 5px">-</span>
<el-input-number v-model="noticeForm.maxArea" controls-position="right" placeholder="最大面积"
:min="0"></el-input-number>
</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-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete(null)">删除
</el-button>
</el-col>
</el-row>
<!-- 表格 -->
<el-table class="notice-table" ref="noticeTable" :data="noticeList" @selection-change="handleSelectionChange"
:row-key="getRowKey" v-loading="loading" style="width: 100%">
<el-table-column type="selection" width="55" align="center" />
<el-table-column type="index" label="序号"> </el-table-column>
<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="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-column label="是否紧急" align="center" prop="urgentFlag">
<template slot-scope="scope">
<el-button v-if="scope.row.urgentFlag === 1" type="danger" plain disabled>紧急</el-button>
<el-button v-if="scope.row.urgentFlag === 2" type="warning" plain disabled>不紧急</el-button>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)">生成工单
</el-button>
</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>
<!-- 新增弹窗 -->
<el-dialog title="生成表单" :visible.sync="addVisible" width="90%" append-to-body :close-on-click-modal="false"
destroy-on-close @close="addCancel">
<edit-dialog v-if="addVisible" :segmentList="segmentList" :tableDefect="tableDefect" :dialogItem="dialogItem"
@cancel="addCancel" />
</el-dialog>
<!-- 查看图片大图 -->
<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 EditDialog from "./components/edit-dialog.vue";
import {
getSegment,
getDefectList,
getMaintenanceNoticeList,
} from "@/api/xj/document";
export default {
name: "MaintenanceNotice",
components: {
EditDialog,
},
data() {
return {
// 查询表单
noticeForm: {
// 道路名称
segmentId: "",
// 上下行
inspectDirection: "",
// 是否紧急
urgentFlag: "",
// 公里桩
stakeStart: undefined,
stakeEnd: undefined,
// 病害长度
minLen: undefined,
maxLen: undefined,
// 病害面积
minArea: undefined,
maxArea: undefined,
},
// 接口查询表单
searchForm: {},
// 查询表单验证
noticeFormRules: {
stakeRange: [
{
required: false,
trigger: "blur",
validator: (rules, value, callback) => {
if (!this.noticeForm.stakeStart && !this.noticeForm.stakeEnd) {
callback();
}
// 验证公里桩格式 K1234+123
const pattern = /^K\d{4}\+\d{3}$/;
if (!pattern.test(this.noticeForm.stakeStart)) {
callback(new Error("起始公里桩格式错误"));
return;
}
if (!pattern.test(this.noticeForm.stakeEnd)) {
callback(new Error("终止公里桩格式错误"));
return;
}
callback();
},
},
],
stakeStart: [
{ required: true, pattern: /^K\d{4}\+\d{3}$/, trigger: "blur" },
],
stakeEnd: [
{ required: true, pattern: /^K\d{4}\+\d{3}$/, trigger: "blur" },
],
},
// 采集时间
dateTime: [],
// 病害类型
paramsDefectType: [],
// 道路名称下拉
segmentList: [],
// 病害类型下拉级联
tableDefect: [],
// 病害总长度
lengthSum: "",
// 病害总面积
areaSum: "",
// 表格加载状态
loading: false,
// 表格数据
noticeList: [],
// 表格总数
tableTotal: 0,
// 分页
pagination: {
page: 1,
size: 10,
},
// 非多个禁用
multiple: true,
// 列表勾选数组
checkIds: [],
// 编辑弹窗信息绑定
dialogItem: [],
// 编辑弹窗显隐控制
addVisible: false,
// 查看弹窗显隐控制
viewVisible: false,
// 查看图片大图弹窗显隐控制
showImageDialog: false,
// 查看大图片路径
currentImageItem: {},
// 图片病害位置信息
rects: [],
};
},
created() {
this.getList();
this.getSegmentList();
this.getDefectData();
},
methods: {
/**
* @description: 获取路段下拉数据
* @return {*}
*/
getSegmentList() {
getSegment().then(({ code, data }) => {
if (code === 200) {
this.segmentList = data;
}
});
},
/**
* @description: 获取病害类型下拉数据
* @return {*}
*/
getDefectData() {
getDefectList().then(({ code, data }) => {
if (code === 200) {
this.tableDefect = data;
}
});
},
/**
* @description: 点击查询
* @param {*}
* @return {*}
*/
handleQuery() {
this.$refs.noticeForm.validate((valid) => {
if (valid) {
const data = {
...this.noticeForm,
classType: this.paramsDefectType ? this.paramsDefectType[0] : "",
defectType: this.paramsDefectType
? this.paramsDefectType.length > 1
? this.paramsDefectType[1]
: ""
: "",
startTime: this.dateTime ? this.dateTime[0] : "",
endTime: this.dateTime ? this.dateTime[1] : "",
};
this.searchForm = JSON.parse(JSON.stringify(data));
this.pagination.page = 1;
this.getList();
}
});
},
/**
* @description: 点击重置
* @param {*}
* @return {*}
*/
resetQuery() {
this.$refs.noticeForm.resetFields();
this.noticeForm = {
// 道路名称
segmentId: "",
// 上下行
inspectDirection: "",
// 是否紧急
urgentFlag: "",
// 公里桩
stakeStart: undefined,
stakeEnd: undefined,
// 病害长度
minLen: undefined,
maxLen: undefined,
// 病害面积
minArea: undefined,
maxArea: undefined,
};
this.paramsDefectType = [];
this.dateTime = [];
this.searchForm = {};
this.pagination.page = 1;
this.getList();
},
/**
* @description: 获取列表数据
* @return {*}
*/
getList() {
this.noticeList = [];
this.loading = true;
const dataItem = {
...this.searchForm,
...this.pagination,
startTime: this.dateTime ? this.dateTime[0] : "",
endTime: this.dateTime ? this.dateTime[1] : "",
maintenanceStatus: "未生成"
};
getMaintenanceNoticeList(dataItem)
.then(({ code, data }) => {
if (code === 200) {
this.noticeList = data.table.rows;
this.tableTotal = data.table.total;
}
})
.finally(() => {
this.loading = false;
});
},
/**
* @description: 列表选择改变事件
* @param {*} selection
* @return {*}
*/
handleSelectionChange(selection) {
this.checkIds = selection.map((item) => item.id);
this.dialogItem = selection;
this.multiple = !selection.length;
},
/**
* @description: 列表行绑定id
* @param {*} row
* @return {*}
*/
getRowKey(row) {
return row.snapshotId;
},
/**
* @description: 点击新增事件
* @param {*} row
* @return {*}
*/
handleAdd() {
this.addVisible = true;
},
/**
* @description: 表格生成工单事件
* @param {*} row
* @return {*}
*/
handleUpdate(row) {
this.dialogItem = [row];
this.addVisible = true;
},
/**
* @description: 表格删除事件
* @param {*} row
* @return {*}
*/
handleDelete(row) {
this.$modal
.confirm(`是否确认删除选中的${[row.id].length}条记录?`)
.then(() => {
// return deleteRoad([row.id]);
})
.then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
})
.catch(() => { });
},
/**
* @description: 切换分页
* @param {*} arg
* @return {*}
*/
handleCurrentChange(arg) {
this.pagination.page = arg;
this.getList();
},
/**
* @description: 切换每页条数
* @param {*} arg
* @return {*}
*/
handleSizeChange(arg) {
this.pagination.size = arg;
this.getList();
},
/**
* @description: 新增弹窗关闭事件
* @param {*}
* @return {*}
*/
addCancel() {
this.addVisible = false;
this.dialogItem = {};
this.getList();
},
/**
* @description: 查看弹窗关闭事件
* @param {*}
* @return {*}
*/
viewCancel() {
this.dialogItem = {};
this.viewVisible = false;
},
/**
* @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: calc(100vh - 5.4rem);
padding: 1rem;
overflow-y: auto;
}
/* 分页样式 */
.pagination-part {
width: 100%;
display: flex;
padding-top: 1rem;
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>