761 lines
20 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: 2024-12-27 14:59:31
* @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="segmentName">
<el-select
v-model="noticeForm.segmentName"
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="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-tabs v-model="activeName" @tab-click="resetQuery">
<el-tab-pane
v-for="(item, index) in editableTabs"
:key="`tabs-${index}`"
:label="item.title"
:name="item.value"
>
<!-- 标签页头 -->
<span slot="label"
><i
v-if="item.status === '1'"
style="color: #67c23a"
class="el-icon-success"
></i>
<i
v-if="item.status === '2'"
style="color: #e6a23c"
class="el-icon-info"
></i>
<i
v-if="item.status === '3'"
style="color: #909399"
class="el-icon-warning"
></i
>{{ item.title }}</span
>
<!-- 表格 -->
<el-table
class="notice-table"
ref="noticeTable"
:data="noticeList"
v-loading="loading"
style="width: 100%"
>
<el-table-column type="index" label="序号"> </el-table-column>
<el-table-column label="路段名称" align="center" prop="segmentName" />
<el-table-column label="采集时间" align="center" prop="createdTime">
<template slot-scope="scope">
<span>{{
new Date(scope.row.createdTime).toLocaleString()
}}</span>
</template>
</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="noticeStatus" />
<el-table-column
label="操作"
align="center"
class-name="small-padding fixed-width"
>
<template slot-scope="scope">
<el-button
v-if="activeName !== '未生成'"
size="mini"
type="text"
icon="el-icon-view"
@click="handleView(scope.row)"
>查看
</el-button>
<el-button
v-if="activeName === '未生成'"
size="mini"
type="text"
icon="el-icon-edit"
@click="handleUpdate(scope.row)"
>生成工单
</el-button>
<el-button
v-if="activeName === '已生成'"
size="mini"
type="text"
icon="el-icon-delete"
@click="handleDelete(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-tab-pane>
</el-tabs>
<!-- 编辑弹窗 -->
<el-dialog
title="生成表单"
:visible.sync="editVisible"
width="40rem"
append-to-body
:close-on-click-modal="false"
destroy-on-close
@close="editCancel"
>
<edit-dialog
v-if="editVisible"
:segmentList="segmentList"
:dialogItem="dialogItem"
@cancel="editCancel"
/>
</el-dialog>
<!-- 查看弹窗 -->
<el-dialog
title="查看表单"
:visible.sync="viewVisible"
width="60rem"
append-to-body
:close-on-click-modal="false"
destroy-on-close
@close="viewCancel"
>
<view-dialog
v-if="viewVisible"
:dialogItem="dialogItem"
@cancel="viewCancel"
/>
</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 ViewDialog from "./components/view-dialog.vue";
import {
getSegment,
getDefectList,
getMaintenanceNoticeList,
} from "@/api/xj/document";
export default {
name: "MaintenanceNotice",
components: {
EditDialog,
ViewDialog,
},
data() {
return {
// 查询表单
noticeForm: {
// 道路名称
segmentName: "",
// 上下行
inspectDirection: "",
// 公里桩
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: [],
// 导航栏选择绑定
activeName: "已完成",
// 导航栏列表
editableTabs: [
{ title: "已完成", value: "已完成", status: "1" },
{ title: "已生成", value: "已生成", status: "2" },
{ title: "未生成", value: "未生成", status: "3" },
],
// 表格加载状态
loading: false,
// 表格数据
noticeList: [],
// 表格总数
tableTotal: 0,
// 分页
pagination: {
page: 1,
size: 10,
},
// 编辑弹窗信息绑定
dialogItem: {},
// 编辑弹窗显隐控制
editVisible: 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 {*}
*/
changeTab() {
this.resetQuery();
},
/**
* @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 = {
// 道路名称
segmentName: "",
// 上下行
inspectDirection: "",
// 公里桩
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.loading = true;
const data = {
...this.searchForm,
...this.pagination,
maintenanceStatus: this.activeName,
};
getMaintenanceNoticeList(data)
.then(({ code, rows, total }) => {
if (code === 200) {
this.noticeList = rows;
this.tableTotal = total;
}
})
.finally(() => {
this.loading = false;
});
},
/**
* @description: 表格查看事件
* @param {*} row
* @return {*}
*/
handleView(row) {
this.dialogItem = row;
this.viewVisible = true;
},
/**
* @description: 表格编辑事件
* @param {*} row
* @return {*}
*/
handleUpdate(row) {
this.dialogItem = row;
this.editVisible = 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 {*}
*/
editCancel() {
this.editVisible = 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>