完成巡检计划

This commit is contained in:
Zy
2026-04-21 14:43:21 +08:00
parent df20099dfd
commit 48852a33ec
7 changed files with 952 additions and 109 deletions

View File

@@ -12,7 +12,7 @@ export interface PlanVO {
/** /**
* 巡检人员ID多个用逗号分隔 * 巡检人员ID多个用逗号分隔
*/ */
inspectorIds: string | number; inspectorIds: string;
/** /**
* 执行周期,如:开始日期-结束日期 * 执行周期,如:开始日期-结束日期
@@ -32,12 +32,12 @@ export interface PlanVO {
/** /**
* 巡检设置0-必须拍照1-可以跳检 * 巡检设置0-必须拍照1-可以跳检
*/ */
inspectSetting: number; inspectSetting: string;
/** /**
* 计划路线,多个用逗号分隔 * 计划路线,多个用逗号分隔
*/ */
routeIds: string | number; routeIds: string;
/** /**
* 状态0-关闭1-开启 * 状态0-关闭1-开启
@@ -53,6 +53,23 @@ export interface PlanVO {
* 执行周期具体日期 * 执行周期具体日期
*/ */
executeDay: string; executeDay: string;
/** 巡检人员信息 */
inspectorList: {
'userId': string;
'userName': string;
'nickName': string;
'phonenumber': number;
}[];
/** 巡检路线 */
routeList: {
'id': string;
'routeName': string;
'description': string;
'totalPoints': string;
'estimatedTime': number;
'routeStatus': string;
}[];
} }
export interface PlanForm extends BaseEntity { export interface PlanForm extends BaseEntity {
@@ -69,7 +86,7 @@ export interface PlanForm extends BaseEntity {
/** /**
* 巡检人员ID多个用逗号分隔 * 巡检人员ID多个用逗号分隔
*/ */
inspectorIds?: string | number; inspectorIds?: string;
/** /**
* 执行周期,如:开始日期-结束日期 * 执行周期,如:开始日期-结束日期
@@ -89,12 +106,12 @@ export interface PlanForm extends BaseEntity {
/** /**
* 巡检设置0-必须拍照1-可以跳检 * 巡检设置0-必须拍照1-可以跳检
*/ */
inspectSetting?: number; inspectSetting?: string;
/** /**
* 计划路线,多个用逗号分隔 * 计划路线,多个用逗号分隔
*/ */
routeIds?: string | number; routeIds?: string;
/** /**
* 状态0-关闭1-开启 * 状态0-关闭1-开启
@@ -121,7 +138,7 @@ export interface PlanQuery extends PageQuery {
/** /**
* 巡检人员ID多个用逗号分隔 * 巡检人员ID多个用逗号分隔
*/ */
inspectorIds?: string | number; inspectorIds?: string;
/** /**
* 执行周期,如:开始日期-结束日期 * 执行周期,如:开始日期-结束日期
@@ -141,12 +158,12 @@ export interface PlanQuery extends PageQuery {
/** /**
* 巡检设置0-必须拍照1-可以跳检 * 巡检设置0-必须拍照1-可以跳检
*/ */
inspectSetting?: number; inspectSetting?: string;
/** /**
* 计划路线,多个用逗号分隔 * 计划路线,多个用逗号分隔
*/ */
routeIds?: string | number; routeIds?: string;
/** /**
* 状态0-关闭1-开启 * 状态0-关闭1-开启

View File

@@ -0,0 +1,62 @@
import request from '@/utils/request';
import { AxiosPromise } from 'axios';
import { TaskVO, TaskForm, TaskQuery } from './type';
/**
* 查询巡检任务列表
* @param query
* @returns {*}
*/
export const listTask = (query?: TaskQuery): AxiosPromise<TaskVO[]> => {
return request({
url: '/inspection/task/list',
method: 'get',
params: query
});
};
/**
* 查询巡检任务详细
* @param id
*/
export const getTask = (id: string | number): AxiosPromise<TaskVO> => {
return request({
url: '/inspection/task/' + id,
method: 'get'
});
};
/**
* 新增巡检任务
* @param data
*/
export const addTask = (data: TaskForm) => {
return request({
url: '/inspection/task',
method: 'post',
data: data
});
};
/**
* 修改巡检任务
* @param data
*/
export const updateTask = (data: TaskForm) => {
return request({
url: '/inspection/task',
method: 'put',
data: data
});
};
/**
* 删除巡检任务
* @param id
*/
export const delTask = (id: string | number | Array<string | number>) => {
return request({
url: '/inspection/task/' + id,
method: 'delete'
});
};

View File

@@ -0,0 +1,195 @@
export interface TaskVO {
/**
* 主键ID
*/
id: string | number;
/**
* 巡检任务名称
*/
taskName: string;
/**
* 关联巡检计划ID
*/
planId: string | number;
/**
* 巡检人员ID
*/
inspectorId: string | number;
/**
* 巡检路线ID
*/
routeId: string | number;
/**
* 起止日期
*/
taskTime: string;
/**
* 巡检设置0-必须拍照1-可以跳检
*/
inspectSetting: number;
/**
* 费用单位
*/
costUnit: string;
/**
* 状态0-待执行1-执行中2-已完成3-已超时
*/
status: string;
/**
* 实际开始时间
*/
actualStartTime: string;
/**
* 实际结束时间
*/
actualEndTime: string;
/**
* 备注
*/
remark: string;
/**
* 提醒时间
*/
remindTime: string;
}
export interface TaskForm extends BaseEntity {
/**
* 主键ID
*/
id?: string | number;
/**
* 巡检任务名称
*/
taskName?: string;
/**
* 关联巡检计划ID
*/
planId?: string | number;
/**
* 巡检人员ID
*/
inspectorId?: string | number;
/**
* 巡检路线ID
*/
routeId?: string | number;
/**
* 起止日期
*/
taskTime?: string;
/**
* 巡检设置0-必须拍照1-可以跳检
*/
inspectSetting?: number;
/**
* 费用单位
*/
costUnit?: string;
/**
* 状态0-待执行1-执行中2-已完成3-已超时
*/
status?: string;
/**
* 实际开始时间
*/
actualStartTime?: string;
/**
* 实际结束时间
*/
actualEndTime?: string;
/**
* 备注
*/
remark?: string;
/**
* 提醒时间
*/
remindTime?: string;
}
export interface TaskQuery extends PageQuery {
/**
* 巡检任务名称
*/
taskName?: string;
/**
* 关联巡检计划ID
*/
planId?: string | number;
/**
* 巡检人员ID
*/
inspectorId?: string | number;
/**
* 巡检路线ID
*/
routeId?: string | number;
/**
* 起止日期
*/
taskTime?: string;
/**
* 巡检设置0-必须拍照1-可以跳检
*/
inspectSetting?: number;
/**
* 费用单位
*/
costUnit?: string;
/**
* 状态0-待执行1-执行中2-已完成3-已超时
*/
status?: string;
/**
* 实际开始时间
*/
actualStartTime?: string;
/**
* 实际结束时间
*/
actualEndTime?: string;
/**
* 提醒时间
*/
remindTime?: string;
/**
* 日期范围参数
*/
params?: any;
}

View File

@@ -1,17 +1,18 @@
<template> <template>
<div class="residentBox" @click="choiceResidentFun"> <slot v-if="$slots.default" />
<div v-else class="residentBox" @click="choiceResidentFun">
<div class="defaultbox" v-if="multipleSelection.length === 0"> <div class="defaultbox" v-if="multipleSelection.length === 0">
<span>请选择</span> <span>请选择</span>
<el-icon><Search /></el-icon> <el-icon><Search /></el-icon>
</div> </div>
<div v-else class="overflow-auto overflow-hidden w-full text-ellipsis text-nowrap"> <div v-else class="overflow-auto overflow-hidden w-full text-ellipsis text-nowrap">
<span>姓名{{ multipleSelection[0] && multipleSelection[0].nickName }}</span> <span>姓名{{ multipleSelection[0]?.name }}</span>
<span v-show="multipleSelection[0] && multipleSelection[0].phonenumber" class="ml-20px">联系方式{{ multipleSelection[0].phonenumber }}</span>
</div> </div>
</div> </div>
<el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050"> <el-dialog append-to-body v-model="dialog.dialogVisible" :title="dialog.dialogTitle" width="1050">
<el-table @row-click="handleRowClick" ref="multipleTableRef" :data="tableData" border> <el-table @row-click="handleRowClick" ref="multipleTableRef" :data="tableData" border @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" align="center" width="55" type="index" /> <el-table-column label="序号" align="center" width="55" type="index" />
<el-table-column label="姓名" align="center" prop="nickName" /> <el-table-column label="姓名" align="center" prop="nickName" />
@@ -20,17 +21,8 @@
<dict-tag :options="sys_user_sex" :value="row.sex" /> <dict-tag :options="sys_user_sex" :value="row.sex" />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="角色" align="center" width="85" prop="userType"> <el-table-column label="角色" align="center" width="85" prop="roleName" />
<template #default="{ row }">
<dict-tag :options="com_resident_type" :value="row.type" />
</template>
</el-table-column>
<el-table-column label="手机号码" align="center" prop="phonenumber" /> <el-table-column label="手机号码" align="center" prop="phonenumber" />
<el-table-column label="状态" align="center" width="85" prop="status">
<template #default="{ row }">
<dict-tag :options="com_certification_status" :value="row.status" />
</template>
</el-table-column>
</el-table> </el-table>
<template #footer> <template #footer>
@@ -75,16 +67,31 @@ const props = defineProps({
returnvalue: { returnvalue: {
type: String, type: String,
default: 'id' default: 'id'
},
titleName: {
type: String,
default: '选择维修人员'
},
userType: {
type: String,
default: 'repair'
},
isMultiple: {
type: Boolean,
default: false
} }
}); });
const { userid } = toRefs(props);
const { userid, titleName, userType, returnvalue } = toRefs(props);
// ✅ 手动设置默认值(替代 withDefaults
const emit = defineEmits<{ const emit = defineEmits<{
change: [value: string | number | tableType]; change: [value: string | number | (string | number)[] | tableType | tableType[]]; // 支持返回数组
}>(); }>();
const dialog = ref({ const dialog = ref({
dialogVisible: false, dialogVisible: false,
dialogTitle: '选择维修人员' dialogTitle: titleName.value
}); });
const queryParams = ref({ const queryParams = ref({
@@ -105,35 +112,30 @@ const multipleTableRef = ref();
const tableData = ref<tableType[]>([]); const tableData = ref<tableType[]>([]);
const total = ref(0); const total = ref(0);
const loading = ref(false); const loading = ref(false);
const treedata = ref([]);
// 存储选中项 // 存储选中项
const multipleSelection = ref<tableType[]>([]); const multipleSelection = ref<tableType[]>([]);
// 单选点击事件(完全替代 selection-change const isMultiple = computed(() => props.isMultiple ?? false);
const handleRowClick = (row: tableType) => {
multipleTableRef.value?.clearSelection();
multipleTableRef.value?.toggleRowSelection(row, true);
multipleSelection.value = [row];
};
// 统一回显 userid 选中(安全版) // 优化 handleUserSelection避免重复查找
const handleUserSelection = () => { const handleUserSelection = () => {
if (!userid.value || !tableData.value.length) return; if (!userid.value || !tableData.value.length) return;
const target = tableData.value.find((item) => item.userId == userid.value); const target = tableData.value.find((item) => item.userId == userid.value);
if (target) { if (target && !multipleSelection.value.some((sel) => sel.id === target.id)) {
multipleSelection.value = [target]; multipleSelection.value = [target];
nextTick(() => { nextTick(() => {
multipleTableRef.value?.clearSelection(); multipleTableRef.value?.setSelection([target]);
multipleTableRef.value?.toggleRowSelection(target, true);
}); });
} }
}; };
// 监听 // 监听
// 监听优化:只在 userid 变化时触发
watch(userid, handleUserSelection, { immediate: true }); watch(userid, handleUserSelection, { immediate: true });
watch(tableData, handleUserSelection); watch(tableData, () => {
if (userid.value) handleUserSelection(); // 仅在有 userid 时重新处理
});
// ====================== 方法 ====================== // ====================== 方法 ======================
// 打开选择框 // 打开选择框
@@ -144,13 +146,46 @@ function choiceResidentFun() {
// 获取列表 // 获取列表
function getlist() { function getlist() {
loading.value = true; loading.value = true;
getUserByRoleKey().then((res) => { getUserByRoleKey(userType.value)
tableData.value = res.data; .then((res) => {
total.value = res.total; tableData.value = res.data;
loading.value = false; total.value = res.total;
}); })
.catch((error) => {
console.error('获取用户列表失败:', error);
})
.finally(() => {
loading.value = false;
});
} }
// ==============================================
// ✅ 新增:处理 selection-change多选专用
// ==============================================
function handleSelectionChange(selection: tableType[]) {
if (isMultiple.value) {
multipleSelection.value = selection;
}
}
// ==============================================
// 最佳单选方案:点击行选中,无报错、无循环、最稳定
// ==============================================
// 优化 handleRowClick避免重复
function handleRowClick(row: tableType) {
if (isMultiple.value) {
const index = multipleSelection.value.findIndex((item) => item.id === row.id);
if (index > -1) {
multipleSelection.value.splice(index, 1);
multipleTableRef.value?.toggleRowSelection(row, false);
} else {
multipleSelection.value.push(row);
multipleTableRef.value?.toggleRowSelection(row, true);
}
} else {
multipleSelection.value = [row];
multipleTableRef.value?.setSelection([row]);
}
}
// 重置查询 // 重置查询
function resetQuery() { function resetQuery() {
queryParams.value = { queryParams.value = {
@@ -175,21 +210,45 @@ function conback() {
resetQuery(); resetQuery();
} }
// 确定 // ==============================================
// ✅ 核心修改:根据 returnvalue 返回对应的值
// ==============================================
function confirm() { function confirm() {
dialog.value.dialogVisible = false; dialog.value.dialogVisible = false;
console.log(multipleSelection.value, props.returnvalue);
if (multipleSelection.value.length > 0) { if (multipleSelection.value.length > 0) {
if (props.returnvalue === 'id') { if (isMultiple.value) {
emit('change', multipleSelection.value[0].userId); // 多选
} else if (props.returnvalue === 'value') { if (returnvalue.value === '*') {
emit('change', multipleSelection.value[0]); // ✅ 返回整个对象数组
emit('change', multipleSelection.value);
} else {
// 返回指定字段数组
emit(
'change',
multipleSelection.value.map((item) => item[returnvalue.value as keyof tableType])
);
}
} else {
// 单选
if (returnvalue.value === '*') {
// ✅ 返回整个对象
emit('change', multipleSelection.value[0]);
} else {
console.log(multipleSelection.value[0], returnvalue.value);
// 返回指定字段
emit('change', multipleSelection.value[0][returnvalue.value as keyof tableType]);
}
} }
} }
} }
// 初始化 // 初始化
getlist(); getlist();
defineExpose({
open: () => {
dialog.value.dialogVisible = true;
}
});
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">

View File

@@ -6,12 +6,27 @@
<div>基本信息</div> <div>基本信息</div>
</div> </div>
<div class="bodybox"> <div class="bodybox">
<el-form label-width="100px" label-position="right"> <el-form ref="formRef" :model="form" :rules="rules" label-width="120px" label-position="right">
<el-form-item label="巡检计划名称" prop="planName"> <el-form-item label="巡检计划名称" prop="planName">
<el-input v-model="form.planName" placeholder="请输入"></el-input> <el-input v-model="form.planName" placeholder="请输入"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="巡检人员" prop="inspectorIds"> <el-form-item label="巡检人员" prop="inspectorIds">
<el-input v-model="form.inspectorIds" placeholder="请输入"></el-input> <div class="inspectorIdsBox">
<div v-for="(item, index) in checkoutUserlist" :key="index" class="inspector_items">
<div class="name">{{ item.nickName }}</div>
<i @click="handleDelete" class="deleteaction">
<el-icon><Delete /></el-icon>
</i>
</div>
<RepairUser @change="handleUserChange" returnvalue="*" :is-multiple="true" user-type="inspection" ref="RepairUserRef">
<template #default>
<div @click="handleAddUser" class="inspector_items add flex flex-items-center justify-center">
<el-icon><Plus /></el-icon>
<span class="ml-10px"> 添加 </span>
</div>
</template>
</RepairUser>
</div>
</el-form-item> </el-form-item>
<el-form-item label="执行周期"> <el-form-item label="执行周期">
<el-date-picker <el-date-picker
@@ -26,7 +41,7 @@
/> />
</el-form-item> </el-form-item>
<el-form-item label="任务时间"> <el-form-item label="任务时间">
<el-select v-model="form.taskTime" placeholder="Select" style="width: 100%"> <el-select v-model="form.taskTime" placeholder="选择任务时间段" style="width: 100%">
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
<div flex flex-wrap> <div flex flex-wrap>
@@ -47,7 +62,7 @@
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="提醒时间"> <el-form-item label="提醒时间">
<el-select v-model="form.remindTime" placeholder="Select" style="width: 100%"> <el-select v-model="form.remindTime" placeholder="请选择" style="width: 100%">
<el-option v-for="item in remindTimeoptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in remindTimeoptions" :key="item.value" :label="item.label" :value="item.value" />
</el-select> </el-select>
</el-form-item> </el-form-item>
@@ -58,13 +73,13 @@
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="计划路线"> <el-form-item label="计划路线">
<el-select v-model="form.routeIds" placeholder="Select" style="width: 100%"> <el-select @change="handlChangeMap" v-model="form.routeIds" placeholder="请选择" style="width: 100%">
<el-option v-for="item in routeIdsoptions" :key="item.value" :label="item.label" :value="item.value" /> <el-option v-for="item in planlist" :key="item.value" :label="item.routeName" :value="item.id" />
</el-select> </el-select>
<div class="mapbox"></div> <div class="mapbox" id="PlanMapBox"></div>
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button type="primary">提交</el-button> <el-button type="primary" @click="submit">提交</el-button>
<el-button @click="routeback">返回</el-button> <el-button @click="routeback">返回</el-button>
</el-form-item> </el-form-item>
</el-form> </el-form>
@@ -74,38 +89,52 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { listRoute } from '@/api/system/InspectionRoute';
import RepairUser from '@/components/Holder/repairUser.vue';
import PageHeader from '@/components/Pageheader/index.vue'; import PageHeader from '@/components/Pageheader/index.vue';
import { numToWeek } from '@/utils/time'; import { numToWeek } from '@/utils/time';
import { Delete } from '@element-plus/icons-vue';
import { ref } from 'vue'; import { ref } from 'vue';
const route = useRoute(); import AMapLoader from '@amap/amap-jsapi-loader';
import { addPlan, getPlan, updatePlan } from '@/api/system/InspectionPlan';
const route = useRoute();
const router = useRouter(); const router = useRouter();
const form = ref({ const form = ref({
taskTime: 0, id: null,
remindTime: '', planName: '', // 巡检计划名称
startTime: '', inspectorIds: '', // 巡检人员
endTime: '', taskTime: '', // 任务时间段
inspectSetting: '', executeCycle: '', // 执行周期
routeIds: '' executeDay: '', // 执行周期具体的周几
remindTime: '', // 提醒时间
routeIds: '', // 计划路线id
inspectSetting: '1' // 巡检设置
});
const rules = ref({
planName: [{ required: true, message: '请输入巡检计划名称', trigger: 'blur' }],
inspectorIds: [{ required: true, message: '请选择巡检人员', trigger: 'blur' }],
executeCycle: [{ required: true, message: '请输入执行周期', trigger: 'blur' }],
routeIds: [{ required: true, message: '请选择路线', trigger: 'blur' }]
}); });
// 执行周期 // 执行周期
const taskDateSplit = ' - ';
const taskDate = ref([]); const taskDate = ref([]);
function handleTime(val) { function handleTime(val: string[]) {
console.log(val);
taskDate.value = val; taskDate.value = val;
form.value.startTime = val[0]; form.value.executeCycle = `${val[0]}${taskDateSplit}${val[1]}`;
form.value.endTime = val[1];
} }
// 选择周几
const checkoutWeek = ref([]); const checkoutWeek = ref([]);
function checkoutWeekFun(val: number) { function checkoutWeekFun(val: number) {
if (!checkoutWeek.value.includes(val)) { if (!checkoutWeek.value.includes(val)) {
checkoutWeek.value.push(val); checkoutWeek.value.push(val);
form.value.executeDay = checkoutWeek.value.join(',');
} else { } else {
checkoutWeek.value = checkoutWeek.value.filter((item) => item !== val); checkoutWeek.value = checkoutWeek.value.filter((item) => item !== val);
} }
console.log(val);
} }
// 任务时间 // 任务时间
@@ -118,47 +147,162 @@ const options = ref([
// 提醒时间 // 提醒时间
const remindTimeoptions = ref([ const remindTimeoptions = ref([
{ {
value: 0, value: 10,
label: '任务开始前10分钟' label: '任务开始前10分钟'
}, },
{ {
value: 1, value: 15,
label: '任务开始前15分钟' label: '任务开始前15分钟'
}, },
{ {
value: 2, value: 20,
label: '任务开始前30分钟' label: '任务开始前30分钟'
} }
]); ]);
// 计划路线
const routeIdsoptions = ref([
{
value: 0,
label: '常规巡更计划1'
},
{
value: 1,
label: '常规巡更计划2'
},
{
value: 2,
label: '常规巡更计划3'
}
]);
// 巡检计划id // 巡检计划id
const editid = ref(null); const editid = ref(null);
function init() {
// 初始化
// 路线列表
const planlist = ref([]);
async function init() {
const res = await listRoute();
planlist.value = res.rows;
if (route.query.id) { if (route.query.id) {
editid.value = route.query.id; editid.value = route.query.id;
getPlan(editid.value).then((res) => {
form.value = {
id: res.data.id,
planName: res.data.planName, // 巡检计划名称
inspectorIds: res.data.inspectorIds, // 巡检人员
taskTime: res.data.taskTime, // 任务时间段
executeCycle: res.data.executeCycle, // 执行周期
executeDay: res.data.executeDay, // 执行周期具体的周几
remindTime: res.data.remindTime, // 提醒时间
routeIds: res.data.routeIds, // 计划路线id
inspectSetting: String(res.data.inspectSetting) // 巡检设置
};
taskDate.value = res.data.executeCycle.split(taskDateSplit);
checkoutWeek.value = res.data.executeDay
.split(',')
.map((item) => Number(item))
.filter((item) => item);
handlChangeMap(res.data.routeIds);
});
} }
} }
init(); init();
// 选择 巡检人员
const RepairUserRef = ref<InstanceType<typeof RepairUser>>();
function handleAddUser() {
RepairUserRef.value.open();
}
const checkoutUserlist = ref([]);
function handleUserChange(val) {
checkoutUserlist.value = val;
}
function handleDelete(id) {
checkoutUserlist.value = checkoutUserlist.value.filter((item) => item.userId !== id);
}
// 返回
function routeback() { function routeback() {
router.back(); router.back();
} }
const AMapLib = ref(null);
const map = ref(null);
const mapReady = ref(false);
const markerlist = [];
function handlChangeMap(val) {
map.value.remove(markerlist);
if (val) {
const find = planlist.value.find((item) => item.id === val);
if (find) {
if (find.points && find.points.length > 0) {
find.points.forEach((item, index) => {
const lnglat = item.location.split(',').map(Number);
const marker = new AMapLib.value.Marker({
position: new AMapLib.value.LngLat(lnglat[0], lnglat[1]), //经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
title: item.pointName,
content: `
<div style="display:flex;align-items:center;justify-content:center;width:30px;height:30px;line-height:18px;border-radius:50%;background-color:rgba(26,117,255,0.3);">
<div
style=" width: 20px;
border-radius: 50%;
height: 20px;
line-height: 20px;
background-color: rgba(26,117,255,1);
color: #ffffff;
font-size: 20px;
text-align: center;"
>${index + 1}</div>
</div>`
});
//将创建的点标记添加到已有的地图实例:
map.value.add(marker);
markerlist.push(marker);
});
}
if (find.pathPoints && typeof find.pathPoints === 'string') {
const path = JSON.parse(find.pathPoints);
console.log(path);
//创建 Polyline 实例
const polyline = new AMapLib.value.Polyline({
path: path,
strokeWeight: 2, //线条宽度
strokeColor: 'red', //线条颜色
lineJoin: 'round' //折线拐点连接处样式
});
map.value.add(polyline);
markerlist.push(polyline);
}
map.value.setFitView();
}
}
}
onMounted(async () => {
await nextTick();
window._AMapSecurityConfig = { securityJsCode: '09534b3534d8da53968529a9ce164118' };
AMapLoader.load({
key: '8e302fe1be5f4db62bc734db23dca149',
version: '2.0',
plugins: ['AMap.Scale', 'AMap.Marker']
}).then(async (AMap) => {
AMapLib.value = AMap;
map.value = new AMap.Map('PlanMapBox', {
viewMode: '3D',
zoom: 11,
center: [116.397428, 39.90923]
});
mapReady.value = true;
});
});
const formRef = ref();
function submit() {
formRef.value?.validate(async (valid: boolean) => {
if (valid) {
form.value.inspectorIds = checkoutUserlist.value.map((item) => item.userId).join(',');
if (editid.value) {
updatePlan(form.value).then(() => {
ElMessage.success('编辑成功');
routeback();
});
} else {
addPlan(form.value).then(() => {
ElMessage.success('添加成功');
routeback();
});
}
}
});
}
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
@@ -171,6 +315,46 @@ function routeback() {
margin: 0 auto; margin: 0 auto;
margin-top: 20px; margin-top: 20px;
} }
.inspectorIdsBox {
display: flex;
flex-wrap: wrap;
align-items: center;
.inspector_items {
width: 120px;
height: 40px;
line-height: 40px;
margin: 5px;
text-align: center;
border-radius: 5px;
background-color: #ddeaff;
display: flex;
align-items: center;
justify-content: center;
padding: 0 2px;
.name {
overflow: hidden;
text-overflow: ellipsis;
text-wrap: nowrap;
}
&.add {
background-color: #ddeaff25;
border: 1px dashed #ccc;
cursor: pointer;
&:hover {
background-color: rgba(221, 234, 255, 0.199);
border-color: #44a0ff;
color: #44a0ff;
}
}
.deleteaction {
margin-left: 10px;
cursor: pointer;
&:hover {
color: red;
}
}
}
}
.week-items { .week-items {
width: 90px; width: 90px;
height: 30px; height: 30px;
@@ -178,7 +362,7 @@ function routeback() {
border-radius: 5px; border-radius: 5px;
cursor: pointer; cursor: pointer;
margin: 10px 5px; margin: 10px 5px;
background-color: #ccc; border: 1px solid #ccc;
color: #000; color: #000;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -192,6 +376,7 @@ function routeback() {
&.active { &.active {
color: rgba(26, 117, 255, 1); color: rgba(26, 117, 255, 1);
background-color: rgba(26, 117, 255, 0.15); background-color: rgba(26, 117, 255, 0.15);
border: none;
} }
} }

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="p-2"> <div class="h-full flex flex-col p-2">
<Pageheader></Pageheader> <Pageheader></Pageheader>
<transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave"> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div v-show="showSearch" class="mb-[10px]"> <div v-show="showSearch" class="mb-[10px]">
@@ -17,7 +17,7 @@
</div> </div>
</transition> </transition>
<el-card shadow="never"> <el-card class="flex-1" shadow="never">
<template #header> <template #header>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
@@ -38,13 +38,25 @@
<el-table v-loading="loading" border :data="planList" @selection-change="handleSelectionChange"> <el-table v-loading="loading" border :data="planList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="巡检计划名称" align="center" prop="planName" /> <el-table-column label="巡检计划名称" align="center" prop="planName" />
<el-table-column label="巡检人员" align="center" prop="inspectorIds" /> <el-table-column label="巡检人员" align="center" prop="inspectorNames" show-overflow-tooltip />
<el-table-column label="执行周期" align="center" prop="executeCycle" /> <el-table-column label="执行周期" align="center" prop="executeCycle" />
<el-table-column label="执行星期" align="center">
<template #default="scope">
<span v-for="(item, index) in scope.row.executeDayNames" :key="index" class="pl-5px">{{ numToWeek(item) }}</span>
</template>
</el-table-column>
<el-table-column label="任务时间" align="center" prop="taskTime" /> <el-table-column label="任务时间" align="center" prop="taskTime" />
<el-table-column label="巡检设置0-必须拍照1-可以跳检" align="center" prop="inspectSetting" /> <el-table-column label="巡检设置" align="center" prop="inspectSetting">
<el-table-column label="计划路线" align="center" prop="routeIds" /> <template #default="scope">
<el-table-column label="状态0-关闭1-开启" align="center" prop="status" /> <DictTag :options="com_inspection_plan_setting" :value="scope.row.inspectSetting"></DictTag>
<el-table-column label="备注" align="center" prop="remark" /> </template>
</el-table-column>
<el-table-column label="计划路线" align="center" prop="routeNames" />
<el-table-column label="状态" align="center" prop="status">
<template #default="scope">
<el-switch v-model="scope.row.status" :active-value="0" :inactive-value="1" active-text="关闭" inactive-text="开启"></el-switch>
</template>
</el-table-column>
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width"> <el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope"> <template #default="scope">
<el-tooltip content="修改" placement="top"> <el-tooltip content="修改" placement="top">
@@ -65,10 +77,18 @@
<script setup name="Plan" lang="ts"> <script setup name="Plan" lang="ts">
import { listPlan, getPlan, delPlan, addPlan, updatePlan } from '@/api/system/InspectionPlan/index'; import { listPlan, getPlan, delPlan, addPlan, updatePlan } from '@/api/system/InspectionPlan/index';
import { PlanVO, PlanQuery, PlanForm } from '@/api/system/InspectionPlan/type'; import { PlanVO, PlanQuery, PlanForm } from '@/api/system/InspectionPlan/type';
import { numToWeek } from '@/utils/time';
const { proxy } = getCurrentInstance() as ComponentInternalInstance; const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_inspection_plan_setting } = toRefs<any>(proxy?.useDict('com_inspection_plan_setting'));
const planList = ref<PlanVO[]>([]); interface planlistType extends PlanVO {
routeNames?: string;
inspectorNames?: string;
executeDayNames?: number[];
}
const planList = ref<planlistType[]>([]);
const buttonLoading = ref(false); const buttonLoading = ref(false);
const loading = ref(true); const loading = ref(true);
const showSearch = ref(true); const showSearch = ref(true);
@@ -124,6 +144,15 @@ const getList = async () => {
loading.value = true; loading.value = true;
const res = await listPlan(queryParams.value); const res = await listPlan(queryParams.value);
planList.value = res.rows; planList.value = res.rows;
planList.value.forEach((item) => {
item.routeNames = item.routeList.map((item) => item.routeName).join(',');
item.inspectorNames = item.inspectorList.map((item2) => item2.nickName).join(',');
item.executeDayNames = item.executeDay
.split(',')
.sort((a, b) => Number(a) - Number(b))
.map((item) => Number(item));
console.log(item.executeDayNames);
});
total.value = res.total; total.value = res.total;
loading.value = false; loading.value = false;
}; };
@@ -163,14 +192,14 @@ const router = useRouter();
/** 新增按钮操作 */ /** 新增按钮操作 */
const handleAdd = () => { const handleAdd = () => {
router.push({ router.push({
path: '/tool/addInspectionPlan' path: '/inspection/addPlan'
}); });
}; };
/** 修改按钮操作 */ /** 修改按钮操作 */
const handleUpdate = async (row?: PlanVO) => { const handleUpdate = async (row?: PlanVO) => {
router.push({ router.push({
path: '/tool/addInspectionPlan', path: '/inspection/addPlan',
query: { query: {
id: row.id id: row.id
} }
@@ -197,7 +226,7 @@ const submitForm = () => {
/** 删除按钮操作 */ /** 删除按钮操作 */
const handleDelete = async (row?: PlanVO) => { const handleDelete = async (row?: PlanVO) => {
const _ids = row?.id || ids.value; const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除巡检计划编号为"' + _ids + '"的数据项').finally(() => (loading.value = false)); await proxy?.$modal.confirm('是否确认删除巡检计划?').finally(() => (loading.value = false));
await delPlan(_ids); await delPlan(_ids);
proxy?.$modal.msgSuccess('删除成功'); proxy?.$modal.msgSuccess('删除成功');
await getList(); await getList();
@@ -218,3 +247,8 @@ onMounted(() => {
getList(); getList();
}); });
</script> </script>
<style lang="scss" scoped>
.el-table {
height: calc(100% - 80px);
}
</style>

View File

@@ -1,12 +1,303 @@
<template> <template>
<div class="p-2 h-full flex flex-col"> <div class="p-2">
<Pageheader></Pageheader> <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
<div class="flex-1 color-gray flex h-full font-size-6 flex-center">系统还在维护中敬请期待...</div> <div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
<el-form-item label="执行状态" prop="taskName">
<el-input v-model="queryParams.taskName" placeholder="请输入巡检任务名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="巡检任务名称" prop="taskName">
<el-input v-model="queryParams.taskName" placeholder="请输入巡检任务名称" clearable @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item label="实际开始时间" prop="actualStartTime">
<el-date-picker
clearable
v-model="queryParams.actualStartTime"
type="date"
value-format="YYYY-MM-DD"
placeholder="请选择实际开始时间"
/>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<el-card shadow="never">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['system:task:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['system:task:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['system:task:remove']"
>删除</el-button
>
</el-col>
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
</template>
<el-table v-loading="loading" border :data="taskList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="主键ID" align="center" prop="id" v-if="true" />
<el-table-column label="巡检任务名称" align="center" prop="taskName" />
<el-table-column label="关联巡检计划ID" align="center" prop="planId" />
<el-table-column label="巡检人员ID" align="center" prop="inspectorId" />
<el-table-column label="巡检路线ID" align="center" prop="routeId" />
<el-table-column label="起止日期" align="center" prop="taskTime" />
<el-table-column label="巡检设置0-必须拍照1-可以跳检" align="center" prop="inspectSetting" />
<el-table-column label="费用单位" align="center" prop="costUnit" />
<el-table-column label="状态0-待执行1-执行中2-已完成3-已超时" align="center" prop="status" />
<el-table-column label="实际开始时间" align="center" prop="actualStartTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.actualStartTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="实际结束时间" align="center" prop="actualEndTime" width="180">
<template #default="scope">
<span>{{ parseTime(scope.row.actualEndTime, '{y}-{m}-{d}') }}</span>
</template>
</el-table-column>
<el-table-column label="备注" align="center" prop="remark" />
<el-table-column label="提醒时间" align="center" prop="remindTime" />
<el-table-column label="操作" align="center" fixed="right" class-name="small-padding fixed-width">
<template #default="scope">
<el-tooltip content="修改" placement="top">
<el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:task:edit']"></el-button>
</el-tooltip>
<el-tooltip content="删除" placement="top">
<el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['system:task:remove']"></el-button>
</el-tooltip>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
</el-card>
<!-- 添加或修改巡检任务对话框 -->
<el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
<el-form ref="taskFormRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="巡检任务名称" prop="taskName">
<el-input v-model="form.taskName" placeholder="请输入巡检任务名称" />
</el-form-item>
<el-form-item label="关联巡检计划ID" prop="planId">
<el-input v-model="form.planId" placeholder="请输入关联巡检计划ID" />
</el-form-item>
<el-form-item label="巡检人员ID" prop="inspectorId">
<el-input v-model="form.inspectorId" placeholder="请输入巡检人员ID" />
</el-form-item>
<el-form-item label="巡检路线ID" prop="routeId">
<el-input v-model="form.routeId" placeholder="请输入巡检路线ID" />
</el-form-item>
<el-form-item label="起止日期" prop="taskTime">
<el-input v-model="form.taskTime" placeholder="请输入起止日期" />
</el-form-item>
<el-form-item label="巡检设置0-必须拍照1-可以跳检" prop="inspectSetting">
<el-input v-model="form.inspectSetting" placeholder="请输入巡检设置0-必须拍照1-可以跳检" />
</el-form-item>
<el-form-item label="费用单位" prop="costUnit">
<el-input v-model="form.costUnit" placeholder="请输入费用单位" />
</el-form-item>
<el-form-item label="实际开始时间" prop="actualStartTime">
<el-date-picker
clearable
v-model="form.actualStartTime"
type="datetime"
value-format="YYYY-MM-DD HH:mm:ss"
placeholder="请选择实际开始时间"
>
</el-date-picker>
</el-form-item>
<el-form-item label="实际结束时间" prop="actualEndTime">
<el-date-picker clearable v-model="form.actualEndTime" type="datetime" value-format="YYYY-MM-DD HH:mm:ss" placeholder="请选择实际结束时间">
</el-date-picker>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
</el-form-item>
<el-form-item label="提醒时间" prop="remindTime">
<el-input v-model="form.remindTime" placeholder="请输入提醒时间" />
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button :loading="buttonLoading" type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup name="Task" lang="ts">
import { ref } from 'vue'; import { listTask, getTask, delTask, addTask, updateTask } from '@/api/system/InspectionTask/index';
</script> import { TaskVO, TaskQuery, TaskForm } from '@/api/system/InspectionTask/type';
<style scoped lang="scss"></style> const { proxy } = getCurrentInstance() as ComponentInternalInstance;
const { com_inspection_task_status } = toRefs<any>(proxy?.useDict('com_inspection_task_status'));
const taskList = ref<TaskVO[]>([]);
const buttonLoading = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const ids = ref<Array<string | number>>([]);
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const queryFormRef = ref<ElFormInstance>();
const taskFormRef = ref<ElFormInstance>();
const dialog = reactive<DialogOption>({
visible: false,
title: ''
});
const initFormData: TaskForm = {
id: undefined,
taskName: undefined,
planId: undefined,
inspectorId: undefined,
routeId: undefined,
taskTime: undefined,
inspectSetting: undefined,
costUnit: undefined,
status: undefined,
actualStartTime: undefined,
actualEndTime: undefined,
remark: undefined,
remindTime: undefined
};
const data = reactive<PageData<TaskForm, TaskQuery>>({
form: { ...initFormData },
queryParams: {
pageNum: 1,
pageSize: 10,
taskName: undefined,
planId: undefined,
inspectorId: undefined,
routeId: undefined,
taskTime: undefined,
inspectSetting: undefined,
costUnit: undefined,
status: undefined,
actualStartTime: undefined,
actualEndTime: undefined,
remindTime: undefined,
params: {}
},
rules: {
id: [{ required: true, message: '主键ID不能为空', trigger: 'blur' }],
taskName: [{ required: true, message: '巡检任务名称不能为空', trigger: 'blur' }]
}
});
const { queryParams, form, rules } = toRefs(data);
/** 查询巡检任务列表 */
const getList = async () => {
loading.value = true;
const res = await listTask(queryParams.value);
taskList.value = res.rows;
total.value = res.total;
loading.value = false;
};
/** 取消按钮 */
const cancel = () => {
reset();
dialog.visible = false;
};
/** 表单重置 */
const reset = () => {
form.value = { ...initFormData };
taskFormRef.value?.resetFields();
};
/** 搜索按钮操作 */
const handleQuery = () => {
queryParams.value.pageNum = 1;
getList();
};
/** 重置按钮操作 */
const resetQuery = () => {
queryFormRef.value?.resetFields();
handleQuery();
};
/** 多选框选中数据 */
const handleSelectionChange = (selection: TaskVO[]) => {
ids.value = selection.map((item) => item.id);
single.value = selection.length != 1;
multiple.value = !selection.length;
};
/** 新增按钮操作 */
const handleAdd = () => {
reset();
dialog.visible = true;
dialog.title = '添加巡检任务';
};
/** 修改按钮操作 */
const handleUpdate = async (row?: TaskVO) => {
reset();
const _id = row?.id || ids.value[0];
const res = await getTask(_id);
Object.assign(form.value, res.data);
dialog.visible = true;
dialog.title = '修改巡检任务';
};
/** 提交按钮 */
const submitForm = () => {
taskFormRef.value?.validate(async (valid: boolean) => {
if (valid) {
buttonLoading.value = true;
if (form.value.id) {
await updateTask(form.value).finally(() => (buttonLoading.value = false));
} else {
await addTask(form.value).finally(() => (buttonLoading.value = false));
}
proxy?.$modal.msgSuccess('操作成功');
dialog.visible = false;
await getList();
}
});
};
/** 删除按钮操作 */
const handleDelete = async (row?: TaskVO) => {
const _ids = row?.id || ids.value;
await proxy?.$modal.confirm('是否确认删除巡检任务编号为"' + _ids + '"的数据项?').finally(() => (loading.value = false));
await delTask(_ids);
proxy?.$modal.msgSuccess('删除成功');
await getList();
};
/** 导出按钮操作 */
const handleExport = () => {
proxy?.download(
'system/task/export',
{
...queryParams.value
},
`task_${new Date().getTime()}.xlsx`
);
};
onMounted(() => {
getList();
});
</script>