/* * @Author: liuhm * @Date: 2024-9-26 14:43:05 * @Last Modified by: liuhm * @Last
Modified time: 2024-9-26 14:43:09 */ /**
|-------------------------------------------------- | | 任务管理 |
|-------------------------------------------------- */
<template>
<el-card class="custom">
<!-- 头部 START -->
<div slot="header" class="plr10 clearfix">
<div class="fl header-seach-box">
<el-form :model="searchFormData" class="fl mr5">
<el-cascader
style="width: 200px"
v-model="searchFormData.orgId"
clearable
class="ml10"
filterable
:options="maintenanceCompanyList"
:props="{
value: 'id',
label: 'name',
emitPath: false,
checkStrictly: true,
children: 'childrenList'
}"
size="mini"
placeholder="请选择管养单位"
></el-cascader>
<el-select
style="width: 200px"
v-model="searchFormData.routeId"
clearable
class="ml10"
filterable
size="mini"
placeholder="请选择巡查路线"
>
<el-option
v-for="item in routerList"
:key="item.id"
:label="item.routeCode"
:value="item.id"
>
</el-option>
</el-select>
<div v-if="hasFunctionCode(functionList, 'PERM_10244')" class="fr ml5">
<el-button size="mini" icon="el-icon-search " @click="searchTable" />
</div>
</el-form>
</div>
</div>
<!-- 头部 END -->
<!-- 内容 START -->
<el-table
v-loading="tableLoading"
size="mini"
:data="dataSource"
:height="`${cardContentHeight + 35}px`"
row-key="id"
style="width: 100%"
border
stripe
:cell-class-name="cellClass"
>
<el-table-column label="序号" width="50" type="index" align="left" />
<el-table-column label="管养单位" prop="orgName" width="230" align="left" />
<el-table-column label="巡查时间" align="center" width="200" show-overflow-tooltip>
<template slot-scope="scope">
<span>{{ `${formatDate(scope.row.inspectStartDate)} -${formatDate(scope.row.inspectEndDate)}` }}</span>
</template>
</el-table-column>
<el-table-column
label="巡查路线"
prop="routeName"
width="280"
align="center"
show-overflow-tooltip
>
<template slot-scope="scope">
<span>{{ scope.row.routeCode +scope.row.routeName }}</span>
</template>
</el-table-column>
<el-table-column
label="巡查状态"
prop="status"
width="100"
align="center"
show-overflow-tooltip
>
<template slot-scope="scope">
<span>{{ scope.row.status | DailyInspectionStatusMap }}</span>
</template>
</el-table-column>
<el-table-column
label="巡检人"
prop="inspectUser"
align="center"
show-overflow-tooltip
/>
<el-table-column
label="记录人"
prop="recorder"
align="center"
show-overflow-tooltip
>
</el-table-column>
<el-table-column label="操作" fixed="right" width="140" align="center">
<template slot-scope="scope">
<ul class="table-button-list">
<!-- <template v-if="hasFunctionCode(functionList, 'PERM_10249')">
<li @click="detailDailyInspection(scope.row)">
<img src="@/assets/images/table/chakan.png" />详情
</li>
</template> -->
<template v-if="hasFunctionCode(functionList, 'PERM_10246')">
<li @click="modifyDailyInspection(scope.row)">
<img src="@/assets/images/table/bianji.png" />编辑
</li>
</template>
<!-- <template v-if="hasFunctionCode(functionList, 'PERM_10247')">
<li @click="deleteDailyInspection(scope.row)">
<img src="@/assets/images/table/shanchu.png" />删除
</li>
</template> -->
</ul>
<!-- <el-button-group>
<template v-if="hasFunctionCode(functionList, 'PERM_10249')">
<el-button
size="mini"
type="primary"
icon="el-icon-view"
@click="detailDailyInspection(scope.row)"
></el-button>
</template>
<template v-if="hasFunctionCode(functionList, 'PERM_10246')">
<el-button
size="mini"
type="primary"
icon="el-icon-edit-outline"
@click="modifyDailyInspection(scope.row)"
></el-button>
</template>
<template v-if="hasFunctionCode(functionList, 'PERM_10247')">
<el-button
size="mini"
type="danger"
icon="el-icon-delete"
@click="deleteDailyInspection(scope.row)"
></el-button>
</template>
<template v-if="hasFunctionCode(functionList, 'PERM_10248')">
<el-button
size="mini"
icon="el-icon-document-checked"
@click="completeDailyInspection(scope.row)"
></el-button>
</template>
</el-button-group> -->
</template>
</el-table-column>
</el-table>
<el-pagination
class="mt10"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="page.pageNo"
:page-sizes="[10, 20, 30, 40, 50]"
:page-size="page.pageSize"
layout="total, sizes, prev, pager, next, jumper"
:total="entityCount"
>
</el-pagination>
<!-- 内容 END -->
<!-- 组件 START -->
<template>
<InspectionDialog ref="InspectionDialog" />
</template>
<!-- 组件 END -->
</el-card>
</template>
<script>
// 接口
import {
getDailyInspectionList,
deleteDailyInspection,
completeDailyInspection,
getDailyDiseaseDetailPageList
} from "@/api/dailyInspection";
import {
getMaintenanceCompanyList,
getRouteList
} from "@/api/commonAnalysis"
// 组件
import InspectionDialog from "./inspection-dialog/InspectionDialog";
// mixin
import autoHeight from "@/mixin/autoHeight";
import { CONFIRM as CONF } from "@/optionsCfg/Message.js";
import { DIALOG_CLOSED_TYPE as DIALOG } from "@/optionsCfg/Constants";
import moment from "moment";
import { mapCfg } from "@/utils";
export default {
name: "DailyInspection",
components: {
InspectionDialog,
},
mixins: [autoHeight],
data() {
return {
searchFormData: {
orgId: "", // 管养单位id
routeId: "", // 巡查路线id
status: "", // 巡查状态
},
tableLoading: false,
dataSource: [],
page: {
pageSize: 20,
pageNo: 1,
},
searchTime:[],
entityCount: 0,
routerList: [],
maintenanceCompanyList:[],
functionList: this.$store.getters.getFunction,
deviceTypeOpt: [], // 设备类型配置
bridgeMonitorTypeOpt: [], // 监测类型列表
isFirstLoad: false,
};
},
created() {
this.isFirstLoad = true;
this.getRouteList();
this.getMaintenanceCompanyList();
this.loadTableData();
},
filters: {
//边坡与路线位置关系
DailyInspectionStatusMap(key) {
const config = mapCfg("Inspection.Daliy.DailyInspectionStatus")();
let name = "";
config.forEach((item) => {
if (item.key === key) {
name = item.value;
}
});
return name;
},
},
computed: {
dailyInspectionStatusConfig() {
const DailyInspectionStatus = mapCfg("Inspection.Daliy.DailyInspectionStatus")().map((item) => {
return {
value: item.key,
label: item.value,
};
});
return DailyInspectionStatus;
},
},
methods: {
// 加载表格数据
loadTableData() {
this.tableLoading = true;
const params = {
pageSize: this.page.pageSize,
pageNo: this.page.pageNo,
status: this.searchFormData.status,
routeId: this.searchFormData.routeId,
orgId: this.searchFormData.orgId,
startTime: this.searchTime && this.searchTime[0],
endTime: this.searchTime && this.searchTime[1],
};
getDailyInspectionList(params)
.then((res) => {
if (res) {
this.dataSource = res.entities || [];
this.entityCount = res.entityCount;
if (res.pageCount < this.page.pageNo) {
this.page.pageNo = res.pageCount;
this.loadTableData();
}
}
})
.catch((e) => {
this.$message.error(e && e.message);
console.warn(e);
})
.finally((_) => {
this.tableLoading = false;
});
},
// 搜索
searchTable() {
this.page.pageNo = 1;
this.loadTableData();
},
// 格式化时间
formatDate(date) {
if (!date) return "";
return moment(date).format(`YYYY-MM-DD`);
},
// 更改一页显示数量时
handleSizeChange(pageSize) {
this.page.pageNo = 1;
this.page.pageSize = pageSize;
this.loadTableData();
},
// 分页改变时
handleCurrentChange(page) {
this.page.pageNo = page;
this.loadTableData();
},
// 获取养护单位列表
async getMaintenanceCompanyList() {
try {
const res = await getMaintenanceCompanyList();
if (res) {
this.maintenanceCompanyList = res;
}
} catch (err) {
console.log(err);
}
},
// 获取巡查路线列表编号
async getRouteList() {
try {
const res = await getRouteList();
if (res) {
this.routerList = res;
}
} catch (err) {
console.log(err);
}
},
// 添加边坡基本信息
addDailyInspection() {
this.$refs["InspectionDialog"].open();
this.$refs["InspectionDialog"].onClosed = (args) => {
if (DIALOG.CONFIRM === args.option) {
this.page.pageNo = 1;
this.loadTableData();
}
};
},
//查看边坡基本信息
async detailDailyInspection(row) {
try {
// this.$store.commit("SHOW_WAITING");
this.$refs["InspectionDialog"].open(row);
this.$refs["InspectionDialog"].onClosed = (args) => {
if (DIALOG.CONFIRM === args.option) {
// this.page.pageNo = 1
this.loadTableData();
}
};
} catch (e) {
console.warn(e);
this.$store.commit("CLOSE_WAITING");
}
},
// 修改边坡基本信息
async modifyDailyInspection(row) {
try {
this.$store.commit("SHOW_WAITING");
this.$refs["InspectionDialog"].open(row);
this.$refs["InspectionDialog"].onClosed = (args) => {
if (DIALOG.CONFIRM === args.option) {
// this.page.pageNo = 1
this.loadTableData();
}
};
} catch (e) {
console.warn(e);
this.$store.commit("CLOSE_WAITING");
}finally {
this.$store.commit("CLOSE_WAITING");
}
},
// 删除项目
async deleteDailyInspection(row) {
try {
await this.$confirm(CONF.DELETE, CONF.TITLE, {
closeOnClickModal: false,
confirmButtonText: CONF.YES,
cancelButtonText: CONF.NO,
type: "warning",
});
} catch (e) {
return;
} // eslint-disable-line
try {
await this.deleteSideSlopeInfo({ dailyId : row.id });
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
}
},
// 删除项目接口
async deleteSideSlopeInfo(id) {
try {
this.$store.commit("SHOW_WAITING");
const res = await deleteDailyInspection(id);
if (res) {
this.page.pageNo = 1;
this.loadTableData();
this.$message.success("删除成功");
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
} finally {
this.$store.commit("CLOSE_WAITING");
}
},
cellClass({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 3) return "table-align";
},
async uploadBridgeDeviceInfo(file) {
// 设备导入
this.$store.commit("SHOW_WAITING");
try {
const formData = new FormData();
formData.append("file", file.file);
const res = await importBridgeDeviceInfo(formData);
if (res) {
this.$message.success("导入成功");
this.page.pageNo = 1;
this.loadTableData();
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
} finally {
this.$store.commit("CLOSE_WAITING");
}
},
downLoadFile() {
if (!this.searchFormData.bridgeId) {
this.$message.warning("请选择桥梁");
return;
}
const bridgeList = this.$store.state.bridge.bridgeList.filter(
(item) => item.id === this.searchFormData.bridgeId
);
if (bridgeList[0] && bridgeList[0].hasOwnProperty("bridgeNo")) {
const bridgeCode = bridgeList[0].bridgeNo;
downloadMonitorDeviceInfo(bridgeCode)
.then((res) => {
if (res && res.message) {
console.warn(res);
this.$message.error(res && res.message);
}
})
.catch((e) => {
this.$message.error(e && e.message);
console.warn(e);
});
} else {
this.$message.warning("暂无桥梁");
}
},
},
};
</script>
<style lang="scss" scoped>
::v-deep .el-button-group > .el-button:not(:last-child) {
margin-right: 0;
}
.header-seach-box {
height: 46px;
box-sizing: border-box;
padding: 9px 0;
}
::v-deep .table-align .el-tooltip {
padding-left: 28%;
text-align: left;
}
::v-deep .el-table th > .cell {
color: #000;
}
::v-deep .el-table th {
background-color: #eff3f8;
}
::v-deep .el-table--striped .el-table__body tr.el-table__row--striped td {
background-color: rgb(239, 243, 248, 0.6);
}
.table-button-list{
grid-template-columns: repeat(1, 1fr);
}
</style>// 巡查任务弹窗
<template>
<el-dialog
:title="dialogTitle"
:visible.sync="dialogVisible"
width="600px"
:close-on-click-modal="false"
@closed="handleClosed"
>
<el-form
ref="inspectionForm"
:model="formData"
:rules="formRules"
label-width="100px"
size="mini"
:disabled="viewMode"
>
<el-row>
<el-col :span="12">
<el-form-item label="管养单位" prop="orgId">
<el-cascader
v-model="formData.orgId"
:options="maintenanceCompanyList"
:props="{
value: 'id',
label: 'name',
checkStrictly: true,
children: 'childrenList',
emitPath: false
}"
placeholder="请选择管养单位"
style="width: 100%"
clearable
></el-cascader>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="formData.taskName" placeholder="请输入任务名称"></el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="巡检路线" prop="routeId">
<el-select v-model="formData.routeId" placeholder="请选择巡检路线" style="width: 100%">
<el-option
v-for="item in routeList"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-radio-group v-model="formData.status" placeholder="请选择状态" style="width: 100%">
<el-radio label="启用" :value="true"></el-radio>
<el-radio label="禁用" :value="false"></el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="巡检周期" prop="inspectionPeriod">
<el-date-picker
v-model="formData.inspectionPeriod"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
style="width: 100%"
></el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="巡检频次" prop="frequency">
<el-select v-model="formData.frequency" placeholder="请选择巡检频次" style="width: 100%">
<el-option
v-for="item in frequencyOptions"
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注">
<el-input
v-model="formData.remark"
type="textarea"
:rows="3"
placeholder="请输入备注信息"
></el-input>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button size="mini" @click="dialogVisible = false">取 消</el-button>
<el-button v-if="!viewMode" type="primary" size="mini" @click="submitForm">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
import { getMaintenanceCompanyList } from '@/api/commonAnalysis';
import { getRouteList } from '@/api/basicInformation';
// import { addInspectionTask, updateInspectionTask, getInspectionTaskDetail } from '@/api/conservation'; // 假设这些API已存在
export default {
name: 'InspectionDialog',
data() {
return {
dialogVisible: false,
dialogType: 'add', // add, edit, view
formData: {
id: '',
orgId: null,
taskName: '',
routeId: '',
frequency: '',
inspectionPeriod: [],
remark: ''
},
formRules: {
orgId: [{ required: true, message: '请选择管养单位', trigger: 'change' }],
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
routeId: [{ required: true, message: '请选择巡检路线', trigger: 'change' }],
frequency: [{ required: true, message: '请选择巡检频次', trigger: 'change' }],
inspectionPeriod: [{ required: true, message: '请选择巡检周期', trigger: 'change' }]
},
maintenanceCompanyList: [],
routeList: [],
frequencyOptions: [
{ label: '每日', value: 'daily' },
{ label: '每周', value: 'weekly' },
{ label: '每月', value: 'monthly' },
{ label: '每季度', value: 'quarterly' },
{ label: '每半年', value: 'semiannually' },
{ label: '每年', value: 'annually' }
],
onClosed: null
};
},
computed: {
dialogTitle() {
const titleMap = {
add: '新建巡查任务',
edit: '修改巡查任务',
view: '巡查任务详情'
};
return titleMap[this.dialogType] || '巡查任务';
},
viewMode() {
return this.dialogType === 'view';
}
},
created() {
this.getMaintenanceCompanyList();
this.getRouteList();
},
methods: {
// 打开弹窗
open(type = 'add', data = null) {
this.dialogType = type;
this.dialogVisible = true;
this.resetForm();
if (data && (type === 'edit' || type === 'view')) {
this.loadTaskDetail(data.id);
}
return new Promise((resolve) => {
this.onClosed = resolve;
});
},
// 重置表单
resetForm() {
this.formData = {
id: '',
orgId: null,
taskName: '',
routeId: '',
frequency: '',
inspectionPeriod: [],
remark: ''
};
// 如果表单已经被渲染,则重置校验结果
this.$nextTick(() => {
this.$refs.inspectionForm && this.$refs.inspectionForm.clearValidate();
});
},
// 加载任务详情
async loadTaskDetail(id) {
try {
this.$store.commit('SHOW_WAITING');
const res = await getInspectionTaskDetail({ id });
if (res) {
// 假设API返回的数据结构与表单一致
this.formData = {
...res,
inspectionPeriod: [res.startDate, res.endDate]
};
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
} finally {
this.$store.commit('CLOSE_WAITING');
}
},
// 提交表单
submitForm() {
this.$refs.inspectionForm.validate(async (valid) => {
if (!valid) return;
try {
this.$store.commit('SHOW_WAITING');
// 处理日期范围
const params = {
...this.formData,
startDate: this.formData.inspectionPeriod[0],
endDate: this.formData.inspectionPeriod[1]
};
delete params.inspectionPeriod;
let res;
if (this.dialogType === 'add') {
res = await addInspectionTask(params);
} else {
res = await updateInspectionTask(params);
}
if (res) {
this.$message.success(`${this.dialogType === 'add' ? '新增' : '修改'}成功`);
this.dialogVisible = false;
this.onClosed && this.onClosed({ option: 'confirm', data: res });
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
} finally {
this.$store.commit('CLOSE_WAITING');
}
});
},
// 弹窗关闭回调
handleClosed() {
this.onClosed && this.onClosed({ option: 'cancel' });
},
// 获取管养单位列表
async getMaintenanceCompanyList() {
try {
const res = await getMaintenanceCompanyList();
if (res) {
this.maintenanceCompanyList = res;
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
}
},
// 获取路线列表
async getRouteList() {
try {
const res = await getRouteList();
if (res) {
this.routeList = res;
}
} catch (e) {
console.warn(e);
this.$message.error(e && e.message);
}
}
}
};
</script>
<style lang="scss" scoped>
.dialog-footer {
text-align: right;
}
</style>
<template>
<div class="project-management-block">
<!-- 弹窗组件 -->
<side-slope-dialog
:visible="dialogVisible"
:mode="currentMode"
:initial-form="currentForm"
@update:visible="dialogVisible = $event"
@success="handleDialogSuccess" />
<div class="project-management-block--header">
<el-form
size="mini"
:inline="true"
class="fr ml10"
align="left">
<el-input
v-model="searchParams.projectName"
placeholder="项目名称或编号"
size="mini"
clearable
@clear="resetSearch"
style="width: 140px;"
class="mr10" />
<el-select
v-model="searchParams.status"
placeholder="项目状态"
size="mini"
clearable
@clear="resetSearch"
style="width: 140px;"
class="mr10">
<el-option
v-for="item in statusOptions"
:key="item.value"
:label="item.label"
:value="item.value"
filterable />
</el-select>
<el-date-picker
v-model="searchProjectDate"
value-format="timestamp"
size="mini"
class="mr10"
type="datetimerange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期">
</el-date-picker>
<el-button
type="primary"
size="mini"
style="width: 80px;"
@click="handleSearch"
class="mr10"
>查询
</el-button>
<el-button
type="success"
size="mini"
style="width: 80px;"
@click="handleAction('create')"
class="mr10"
>新建
</el-button>
</el-form>
</div>
<div class="project-management-block--content" >
<!-- 项目数据表格 -->
<el-table
:data="tableData"
border
stripe
style="width: 100%;
flex: 1;"
height="100%"
row-key="id"
>
<el-table-column
label="序号"
type="index"
width="120">
</el-table-column>
<el-table-column
label="项目名称"
prop="projectName"
width="250">
</el-table-column>
<el-table-column
label="项目编号"
prop="projectCode"
width="220">
</el-table-column>
<el-table-column
label="项目周期"
width="250">
<template slot-scope="scope">
<span v-if="scope.row">{{ `${formatDate(scope.row.projectStartDate)} 至 ${formatDate(scope.row.projectEndDate)}` }}</span>
</template>
</el-table-column>
<el-table-column
label="项目状态"
width="150">
<template slot-scope="scope">
{{ getStatusText(scope.row.status)}}
</template>
</el-table-column>
<el-table-column
label="边坡总数"
prop="sideSlopeTotalCount"
width="150">
</el-table-column>
<el-table-column
label="已完成边坡数"
prop="sideSlopeCompleteCount"
width="194">
</el-table-column>
<el-table-column
label="完成率"
width="150">
<template slot-scope="scope">
{{ `${((scope.row.sideSlopeCompleteCount / scope.row.sideSlopeTotalCount) * 100).toFixed(1)}%` }}
</template>
</el-table-column>
<el-table-column
label="操作"
width="195">
<template
slot-scope="scope">
<div
v-if="scope.row.id"
style="display: flex;
justify-content: center;">
<el-button
size="mini"
type="primary"
@click="handleAction('view', scope.row)"
style="padding: 4px 8px;
font-size: 12px"
>查看
</el-button>
<el-button
size="mini"
type="info"
@click="handleAction('edit', scope.row)"
style="padding: 4px 8px;
font-size: 12px"
>编辑
</el-button>
<el-button
size="mini"
type="danger"
@click="handleAction('delete', scope.row)"
style="padding: 4px 8px;
font-size: 12px"
>删除
</el-button>
</div>
</template>
</el-table-column>
</el-table>
</div>
<div class="project-management-block--footer">
<el-pagination
background
layout="total,prev, pager, next,jumper"
:current-page.sync="pageParams.pageNo"
:page-size="pageParams.pageSize"
:total="pageParams.total"/>
</div>
</div>
</template>
<script>
// 导入模块
import SideSlopeDialog from './SideSlopeDialog.vue' // 项目详情弹窗组件
import { mapCfg } from '@/utils' // 字典配置映射工具
//接口
import {
getPeriodicInspectionPageList,
deletePeriodicInspection
} from '../../api/testProject'
import moment from 'moment'
// 组件定义
export default {
name: 'ProjectManagement', // 组件名称
components: {
SideSlopeDialog // 注册弹窗组件
},
// 数据模型
data() {
return {
// 搜索参数对象
searchParams: {
projectName: '', // 项目名称/编号搜索词
status: '', // 项目状态筛选值
projectStartDate: '', // 项目开始日期
projectEndDate: '' // 项目结束日期
},
// 日期范围选择器绑定值
searchProjectDate: [],
// 表格数据源
tableData: [],
// 分页参数
pageParams: {
pageNo: 1, // 当前页码
pageSize: 10, // 每页条数
total: 0 // 总数据量
},
// 弹窗控制参数
dialogVisible: false, // 弹窗显示状态
currentMode: '', // 弹窗模式: 'create'/'edit'/'view'
currentForm: null // 当前表单数据
}
},
// 监听器
watch: {
//监听日期范围选择器变化:将选择器值同步到搜索参数对象
searchProjectDate(newVal) {
if (newVal && newVal.length === 2) {
this.searchParams.projectStartDate = newVal[0]
this.searchParams.projectEndDate = newVal[1]
} else {
this.searchParams.projectStartDate = ''
this.searchParams.projectEndDate = ''
}
}
},
// 生命周期钩子
async created() {
// 加载表格数据
this.loadTableData()
},
computed:{
statusOptions() {
const dictList = mapCfg('Inspection.Periodic.PeriodicInspectionStatus')()
return dictList.map(item => ({
value: item.key,
label: item.value
}))
},
},
// 方法/函数
methods: {
// 工具方法
//根据状态值获取状态文本
getStatusText(statusValue) {
const option = this.statusOptions.find((opt) => opt.value === statusValue)
return option.label
},
// 格式化时间
formatDate(date) {
if (!date) return "";
return moment(date).format(`YYYY-MM-DD`);
},
// 弹窗操作方法
handleAction(action, row = null) {
if (action === 'create') {
// 新建操作
this.currentMode = 'create'
this.currentForm = {
projectCode: '',
projectName: '',
projectStartDate: '',
projectEndDate: '',
projectUser: '',
remark: '',
sideSlopeDetailList: []
}
this.dialogVisible = true
} else if (action === 'edit') {
// 编辑操作
this.currentMode = 'edit'
this.currentForm = {
...row,
projectStartDate: row.projectStartDate,
projectEndDate: row.projectEndDate
}
this.dialogVisible = true
} else if (action === 'view') {
// 查看操作
this.currentMode = 'view'
this.currentForm = {
...row,
projectStartDate: row.projectStartDate,
projectEndDate: row.projectEndDate
}
this.dialogVisible = true
} else if (action === 'delete') {
// 删除操作
this.deleteItem(row)
}
},
//删除方法
async deleteItem(row) {
try {
// 显示确认对话框
await this.$confirm('确定要删除该项目吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
})
// 调用删除API
await deletePeriodicInspection({ periodicId: row.id })
this.$message.success('删除成功')
// 如果删除的是最后一页的最后一条,返回上一页
if (this.tableData.length === 1 && this.pageParams.pageNo > 1) {
this.pageParams.pageNo -= 1
}
// 重新加载数据
this.loadTableData()
} catch (error) {
// 用户取消删除时不显示错误
if (error !== 'cancel') {
this.$message.error('删除失败')
}}
},
// 弹窗操作成功回调,刷新表格数据(返回第一页)
handleDialogSuccess() {
this.pageParams.pageNo = 1
this.loadTableData()
},
// 数据操作方法
//加载表格数据,根据搜索参数和分页设置获取项目数据
async loadTableData() {
// 转换日期为时间戳格式
const startTime = this.searchParams.projectStartDate
? new Date(this.searchParams.projectStartDate).getTime()
: null
const endTime = this.searchParams.projectEndDate
? new Date(this.searchParams.projectEndDate).getTime()
: null
// 构造API参数
const params = {
pageNo: this.pageParams.pageNo,
pageSize: this.pageParams.pageSize,
searchKey: this.searchParams.projectName,
status: this.searchParams.status,
startTime,
endTime
}
try {
// 调用API获取项目数据
const res = await getPeriodicInspectionPageList(params)
this.tableData = res.entities || []
this.pageParams.total = res.entityCount || 0
} catch (error) {
console.error('加载项目列表失败', error)
this.tableData = []
this.pageParams.total = 0
}
},
//搜索方法重置到第一页并重新加载数据
handleSearch() {
this.pageParams.pageNo = 1
this.loadTableData()
},
//重置搜索条件,清空所有搜索参数并重新加载数据
resetSearch() {
this.searchParams = {
projectName: '',
status: '',
projectStartDate: '',
projectEndDate: ''
}
this.searchProjectDate = []
this.handleSearch()
},
}
}
</script>
<style lang="scss" scoped>
.project-management-block {
width: 100%;
height: 100%;
position: relative;
background-color: #fff;
&--header {
height: 50px;
box-sizing: border-box;
padding: 10px;
border-bottom: 1px solid #ebeef5;
}
&--content {
display: block;
padding: 10px;
height: calc(100% - 90px);
position: relative;
z-index: 10;
}
&--footer {
border-top: 1px solid #ebeef5;
padding: 4px 10px 0 10px;
position: relative;
z-index: 11;
text-align: center;
}
}
/* 优化表格样式 */
::v-deep .el-table {
flex: 1;
min-height: 0; // 防止flex布局溢出
/* 单元格样式 */
th,
td {
padding: 4px 0;
}
/* 表头样式 */
.el-table__header-wrapper {
line-height: 1;
th {
.cell {
line-height: 1.2;
}
}
}
}
/* 分页组件样式优化,确保在不同缩放比例下可见 */
::v-deep .el-pagination {
padding: 4px 5px;
.btn-prev,
.btn-next,
.el-pager li,
.el-pagination__jump {
min-width: 28px;
height: 28px;
line-height: 28px;
margin: 0 2px;
}
.el-pagination__total,
.el-pagination__jump {
font-size: 12px;
}
}
/* 响应式调整 */
@media screen and (max-width: 1200px) {
.project-management-block--header .el-col {
margin-bottom: 8px;
}
::v-deep .el-pagination {
display: flex;
flex-wrap: wrap;
justify-content: center;
&>* {
margin-bottom: 5px;
}
}
}
</style>/*-----------弹窗模块管理------------------- */
<template>
<el-dialog :title="dialogMode === 'create' ? '新建' : dialogMode === 'edit' ? '修改' : '查看'" :visible.sync="dialogVisible"
:modal-append-to-body="true" append-to-body :close-on-click-modal="false" custom-class="fixed-height-dialog"
width="60%" top="5vh">
<el-form label-width="80px" ref="formRef" :model="currentForm" style="height: 100%;
display: flex;
flex-direction: column;" :rules="rules">
<!-- 项目信息区域 -->
<div class="formBorder">
<el-row :gutter="10">
<el-col :span="6">
<el-form-item size="mini" label="项目名称" prop="projectName">
<el-input v-model="currentForm.projectName" clearable style="width:100%" size="mini"
:disabled="dialogMode === 'view'">
</el-input>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item size="mini" label="项目编号" prop="projectCode">
<el-input v-model="currentForm.projectCode" clearable style="width:100%" size="mini"
:disabled="dialogMode === 'view'">
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item size="mini" label="项目周期" prop="projectDate">
<el-date-picker v-model="projectDate" range-separator="→" start-placeholder="请选择开始日期"
end-placeholder="请选择结束日期" type="daterange" size="mini" style="width: 100%;" unlink-panels
:disabled="dialogMode === 'view'">
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="6">
<el-form-item label="负责人" size="mini" style="width:
fit-content;">
<el-input v-model="currentForm.projectUser" clearable style="width:100%" size="mini"
:disabled="dialogMode === 'view'">
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="项目概述">
<el-input v-model="currentForm.remark" :rows="2" :disabled="dialogMode === 'view'">
</el-input>
</el-form-item>
</el-col>
</el-row>
</div>
<div class="formBorder2">
<el-container style="height: 100%;">
<el-header style="height: auto;
flex-shrink: 0;
padding-bottom: 10px;">
<el-row :gutter="10" type="flex" class="searchDialog">
<el-col :span="5">
<el-select v-model="filterForm.maintenanceCompanyName" placeholder="请选择管养单位" size="mini" clearable
filterable @clear="resetSearch" :disabled="dialogMode === 'view'">
<el-option v-for="item in MaintenanceUnitoptions" :key="item.value" :label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
<el-col :span="5">
<el-select v-model="filterForm.routeCode" placeholder="请选择路线编号" size="mini" clearable filterable
@clear="resetSearch" :disabled="dialogMode === 'view'">
<el-option v-for="item in routeCodeOptions" :key="item.value" :label="item.label" :value="item.value">
</el-option>
</el-select>
</el-col>
<el-col :span="5">
<el-input v-model="filterForm.searchKey" placeholder="请输入边坡编号或名称" size="mini" clearable
@keyup.enter.native="searchForm" @clear="resetSearch" :disabled="dialogMode === 'view'">
<i slot="suffix" class="el-input__icon el-icon-search"></i>
</el-input>
</el-col>
<el-col :span="5">
<el-select v-model="filterForm.evaluateLevel" placeholder="请选择技术状态等级" size="mini" clearable
@clear="resetSearch" :disabled="dialogMode === 'view'">
<el-option v-for="item in getEvaluateLevel" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</el-col>
<el-col :span="2" :offset="4">
<el-button type="primary" size="mini" style="width:100%" icon="el-icon-search" @click="searchForm"
:loading="loading" :disabled="dialogMode === 'view'">搜索
</el-button>
</el-col>
</el-row>
</el-header>
<el-main style="overflow-y: hidden;">
<el-table ref="scrollTable" v-loading="loading" style="width: 100%;" border :data="formTabledata"
:row-style="{ height: '36px' }" :cell-style="{ padding: '4px 0', textAlign: 'center' }"
:header-cell-style="{
height: '36px',
padding: '4px 0',
lineHeight: '36px',
textAlign: 'center'
}" @selection-change="handleSelectionChange" :row-key="getRowkey">
<el-table-column type="selection" width="55" :selectable="isRowSelectable" :reserve-selection="true">
</el-table-column>
<el-table-column label="管养单位" prop="maintenanceCompanyName" width="290" show-overflow-tooltip>
</el-table-column>
<el-table-column label="路线编号" prop="routeCode" width="100">
</el-table-column>
<el-table-column label="边坡编号" prop="sideSlopeCode" width="240" show-overflow-tooltip>
</el-table-column>
<el-table-column label="边坡名称" prop="sideSlopeName" width="267" show-overflow-tooltip>
</el-table-column>
<el-table-column label="技术状态等级" width="137">
<template slot-scope="scope">
{{ mapEvaluateLevel(scope.row.evaluateLevel) }}
</template>
</el-table-column>
</el-table>
</el-main>
<!-- 分页区域 -->
<el-footer style="flex-shrink: 0;
padding-top: 10px;">
<el-pagination background @current-change="handleCurrentChange" :current-page="pageParams.pageNo"
:page-size="pageParams.pageSize" layout="total, prev, pager, next" :total="total">
</el-pagination>
</el-footer>
</el-container>
</div>
</el-form>
<!-- 弹窗底部按钮 -->
<div slot="footer" class="dialog-footer" v-if="dialogMode === 'create' || dialogMode === 'edit'">
<el-button @click="dialogVisible = false">取消
</el-button>
<el-button type="primary" @click="submitForm">提交
</el-button>
</div>
</el-dialog>
</template>
<script>
import { mapCfg } from "@/utils";
import {
getPeriodicInspectionSideSlopePageList,
addPeriodicInspection,
modifyPeriodicInspection,
getSelectedPeriodicInspectionSideSlopeList
} from "../../api/testProject";
import { getMaintenanceCompanyList, getRouteList } from "../../api/basicInformation";
export default {
name: "SideSlopeDialog",
props: {
visible: Boolean, // 控制弹窗显示
mode: String, // 模式:create/edit/view
initialForm: Object, // 初始表单数据
},
data() {
return {
isInitializingSelection: false, // 初始化状态标志
dialogVisible: this.visible, // 弹窗显示状态
dialogMode: this.mode, // 当前模式
currentForm: {
projectCode: '', // 项目编号
projectName: '', // 项目名称
projectStartDate: '', // 开始日期
projectEndDate: '', // 结束日期
projectUser: '', // 项目负责人
remark: '', // 备注
sideSlopeDetailList: [] // 边坡详情列表
},
projectDate: [], // 项目日期范围
total: 0, // 总数据量
loading: false, // 加载状态
pageParams: { // 分页参数
pageNo: 1,
pageSize: 10,
},
filterForm: { // 搜索条件
maintenanceCompanyName: "",
routeCode: "",
searchKey: "",
evaluateLevel: "",
},
mulitipleSelection: [],
allSelection: new Map(),
MaintenanceUnitoptions: [], // 管养单位选项
routeCodeOptions: [], // 路线编号选项
formTabledata: [], // 表格数据
rules: { // 表单验证规则
projectName: [
{ required: true, message: "项目名称不能为空", trigger: "blur" },
],
projectCode: [
{ required: true, message: "项目编码不能为空", trigger: "blur" },
],
},
};
},
watch: {
//监听visible变化时确保加载数据
async visible(val) {
this.dialogVisible = val;
if (val) {
// 打开对话框时重置状态
this.resetAllData();
if (this.dialogMode !== 'create' && this.currentForm.id) {
// 确保在DOM更新后加载数据
await this.$nextTick();
await this.LoadListData();
}
} else {
// 关闭对话框时重置数据
this.resetAllData();
}
},
//监听模式变化
mode(val) {
this.dialogMode = val;
// 当模式从创建变为编辑/查看时,确保加载数据
if (this.dialogVisible && val !== 'create' && this.currentForm.id) {
this.LoadListData();
}
},
// 修复3:监听初始表单数据变化
initialForm: {
deep: true,
immediate: true,
async handler(val) {
this.currentForm = { ...val };
// 安全处理日期(新增空值判断)
this.projectDate = val.projectStartDate && val.projectEndDate
// 关键修复:添加空值校验
if (this.dialogVisible && val.id && this.dialogMode !== 'create') {
await this.$nextTick();
await this.LoadListData();
}
}
},
// 同步弹窗显示状态到父组件
dialogVisible(val) {
this.$emit("update:visible", val);
},
projectDate: {
deep: true,
handler(value) {
if (value && value.length === 2) {
this.currentForm.projectStartDate = value[0];
this.currentForm.projectEndDate = value[1];
}
},
},
},
async created() {
// 初始化数据
this.getRouteList();
this.getMaintenanceCompanyList();
},
computed:{
getEvaluateLevel() {
const levelList = mapCfg("Inspection.Regular.RegularEvaluateLevel")();
return levelList.map((item) => ({
value: item.key,
label: item.value,
}))
},
},
methods: {
handleSelectionChange(selection) {
// 跳过初始化阶段的选中状态变更
if (this.isInitializingSelection) return;
// 获取当前页选中项的key集合
const currentPageKeys = new Set(
selection.map(row => row.sideSlopeUniqueCode)
);
// 处理当前页的取消选中操作
this.formTabledata.forEach(row => {
const key = row.sideSlopeUniqueCode;
// 仅当行在全局选中池中但不在当前页选中集合时删除
if (this.allSelection.has(key) && !currentPageKeys.has(key)) {
this.allSelection.delete(key);
}
});
// 添加新选中的项到全局池
selection.forEach(row => {
const key = row.sideSlopeUniqueCode;
if (!this.allSelection.has(key)) {
this.allSelection.set(key, row);
}
});
// 更新当前页选中引用
this.mulitipleSelection = selection;
},
getRowkey(row) {
return row.sideSlopeUniqueCode;
},
// 判断行是否可选(查看模式禁用选择)
isRowSelectable(row, index) {
return this.dialogMode !== "view";
},
// 获取管养单位列表
async getMaintenanceCompanyList() {
const res = await getMaintenanceCompanyList();
this.MaintenanceUnitoptions = res.map((item) => ({
value: item,
label: item,
}));
},
// 获取路线列表
async getRouteList() {
const res = await getRouteList();
this.routeCodeOptions = res.map((item) => ({
value: item.id,
label: item.routeCode,
}));
},
// 搜索方法
searchForm() {
this.pageParams.pageNo = 1;
this.LoadListData();
},
// 重置搜索条件
resetSearch() {
this.filterForm = {
maintenanceCompanyName: "",
routeCode: "",
searchKey: "",
evaluateLevel: "",
};
this.pageParams.pageNo = 1;
this.LoadListData();
},
// 重置组件状态
resetAllData() {
this.resetSelection();
this.formTabledata = []; // 清空表格数据
this.total = 0; // 重置总条数
this.pageParams = { // 重置分页
pageNo: 1,
pageSize: 10
};
// 重置搜索条件(可选)
this.filterForm = {
maintenanceCompanyName: "",
routeCode: "",
searchKey: "",
evaluateLevel: ""
};
},
// 修改原有方法
resetSelection() {
this.allSelection.clear();
this.allSelection = new Map();
if (this.$refs.scrollTable) {
this.$refs.scrollTable.clearSelection();
}
},
// 映射技术状态等级
mapEvaluateLevel(level) {
const option = this.getEvaluateLevel.find(
(item) => item.value === level
);
return option.label;
},
// 加载表格数据
async LoadListData() {
this.loading = true;
try {
const params = {
orgId: this.filterForm.maintenanceCompanyName,
routeId: this.filterForm.routeCode,
searchKey: this.filterForm.searchKey,
evaluateLevel: this.filterForm.evaluateLevel,
pageSize: this.pageParams.pageSize,
pageNo: this.pageParams.pageNo,
};
// 获取表格数据
const res = await getPeriodicInspectionSideSlopePageList(params);
this.formTabledata = res.entities;
this.total = res.entityCount;
// 处理非创建模式的数据加载
if (this.dialogMode !== 'create' && this.currentForm.id) {
// 首次加载时获取所有选中项
if (this.pageParams.pageNo === 1) {
const selected = await getSelectedPeriodicInspectionSideSlopeList({
periodicId: this.currentForm.id,
pageSize: 10000, // 获取所有选中项
pageNo: 1
});
// 重置全局选中池
this.allSelection.clear();
this.mulitipleSelection = selected.entities;
// 存储全局选中状态
this.mulitipleSelection.forEach(item => {
this.allSelection.set(item.sideSlopeUniqueCode, item);
});
}
// 设置当前页选中状态
this.isInitializingSelection = true;
this.$nextTick(() => {
this.formTabledata.forEach(row => {
if (this.allSelection.has(row.sideSlopeUniqueCode)) {
this.$refs.scrollTable.toggleRowSelection(row, true);
}
});
this.isInitializingSelection = false;
});
}
} catch (error) {
console.error("加载数据失败:", error);
this.$message.error("加载数据失败");
} finally {
this.loading = false;
}
},
// 当前页码变化
handleCurrentChange(val) {
this.pageParams.pageNo = val;
this.LoadListData();
},
// 提交表单
async submitForm() {
this.$refs.formRef.validate(async (valid) => {
if (valid) {
// 验证是否选择了边坡
const selectedItems = Array.from(this.allSelection.values());
if (this.allSelection.size === 0) {
this.$message.warning("请至少选择一个边坡");
return;
}
// 构造提交参数
const params = {
...this.currentForm,
sideSlopeDetailList: selectedItems.map(item => ({
sideSlopeUniqueCode: item.sideSlopeUniqueCode,
evaluateLevel: item.evaluateLevel,
evaluateDate: item.evaluateDate || undefined
})),
};
// 根据模式选择操作
const action = this.dialogMode === "create"
? addPeriodicInspection
: modifyPeriodicInspection;
// 执行操作
try {
const success = await action(params);
if (success) {
this.$message.success(
this.dialogMode === "create" ? "新建成功" : "修改成功"
);
this.$refs.scrollTable.clearSelection();
this.$emit("success");
this.dialogVisible = false;
} else {
this.$message.error("操作失败");
}
} catch (error) {
this.$message.error(error.message || "操作失败");
}
}
});
}
},
};
</script>
<style lang="scss" scoped>
/* 修复1:弹性容器最小高度约束 */
:deep(.fixed-height-dialog),
.formBorder2,
.formBorder2 .el-container,
.formBorder2 .el-main {
min-height: 0 !important;
}
/* 表格行高优化 */
:deep(.el-table) {
.el-table__row {
height: 36px !important;
td {
padding: 4px 0 !important;
}
}
.el-table__header {
th {
padding: 4px 0 !important;
.cell {
line-height: 28px !important;
}
}
}
/* 确保内部滚动 */
.el-table__body-wrapper {
overflow-y: auto !important;
max-height: calc(100vh - 400px) !important;
}
}
/* 表单区域固定 */
.formBorder {
position: relative; ///为伪元素提供定位上下文
border: thin dotted black !important;
padding: 10px !important;
margin-top: 15px !important;
flex-shrink: 0 !important;
height: auto !important;
overflow: visible !important;
margin-bottom: 15px !important;
/* 边框的文字 */
&::before {
content: "项目信息";
position: absolute;
top: -8px; //调整到更合适的位置
left: 15px; //向右移动避免遮挡
background-color: #fff; //背景色需与页面背景一致
padding: 0 8px;
font-size: 13px;
color: #606266;
z-index: 10; //提高层级确保显示
font-weight: 500; //加粗文字
pointer-events: none; //防止点击穿透
}
}
.formBorder2 {
position: relative;
border: thin dotted black;
padding: 10px;
flex: 1;
min-height: 0;
overflow: hidden; // 保留
display: flex;
flex-direction: column;
padding-top: 25px; // 新增
&::before {
content: "待检边坡";
position: absolute;
top: 5px; // 调整到新增的padding区域内部
left: 15px;
background-color: #fff;
padding: 0 8px;
font-size: 13px;
color: #606266;
z-index: 1000;
font-weight: 500;
pointer-events: none;
}
.el-container {
height: auto !important; // 覆盖行内样式
flex: 1; // 填满剩余空间
display: flex;
flex-direction: column;
min-height: 0;
.el-header {
flex-shrink: 0;
height: auto !important;
padding-bottom: 10px;
}
.el-main {
flex: 1;
overflow: hidden;
position: relative;
padding: 0;
}
.el-footer {
flex-shrink: 0;
padding-top: 10px;
}
}
}
// 弹窗底部按钮区域
.dialog-footer {
padding: 10px 20px;
border-top: 1px solid #ebeef5;
text-align: center;
}
// 搜索区域样式
.searchDialog {
margin-top: 5px;
}
// 空数据样式
:deep(.el-table__empty-block) {
min-height: 200px;
display: flex;
justify-content: center;
align-items: center;
}
// 分页样式
:deep(.el-pagination) {
padding: 5px 0;
}
// 表格高度控制
:deep(.el-table) {
height: 100% !important;
.el-table__body-wrapper {
overflow-y: auto !important;
}
}
</style>结合前两段代码的组件方式 后两段代码应该如何修改