You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

467 lines
12 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<el-dialog
:title="title"
v-model="visible"
width="35%"
class="x-dialog"
:destroy-on-close="true"
append-to-body
@closed="handlerClose()"
>
<el-form
class="dialog-data"
:model="form"
:rules="rules"
ref="formRef"
label-width="88px"
>
<el-form-item label="工单地址:" prop="address">
<div class="map">
<MarsMap
:url="configUrl"
:options="getMapOptions"
map-key="workOrder"
@onload="marsOnload"
/>
</div>
<el-input
v-model="form.address"
placeholder="请输入"
clearable
@keyup.enter="handleSearch"
>
<template #prepend>
<el-button icon="MapLocation" />
</template>
<template #append>
<span class="location-search" @click="handleSearch">搜索</span>
</template>
</el-input>
<div class="serch-list" v-show="gaodePOIList.length > 0">
<div
clss="list-item"
:class="currentId === item.id ? 'activeitem' : ''"
v-for="item in gaodePOIList"
:key="item.id"
@click="handleCograph(item)"
>
{{ item.name }}
</div>
</div>
</el-form-item>
<el-form-item label="工单类型:" prop="gdType">
<el-radio-group v-model="form.gdType" @change="changeType()">
<el-radio :value="parseInt(dict.value)" v-for="dict in dict.gdlx">{{
dict.label
}}</el-radio>
</el-radio-group>
</el-form-item>
<section v-if="id">
<el-form-item prop="xdsqm" v-if="form.gdType === 0">
<el-radio-group v-model="form.xdsqm">
<el-radio
:value="parseInt(dict.value)"
v-for="dict in dict.xdsqm"
>{{ dict.label }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item label="影响类型:" prop="yxlx">
<el-checkbox-group v-model="form.yxlx">
<el-checkbox
v-for="dict in dict.yxlx"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-checkbox-group>
</el-form-item>
<el-form-item label="工单照片:" prop="gdtp">
<ImageUpload v-model="form.gdtp" :limit="3"></ImageUpload>
</el-form-item>
</section>
<section v-else>
<el-form-item label="选派班组:" prop="zzjg">
<el-cascader
v-model="form.zzjg"
:options="dict.deptList"
:props="cascaderProps"
@change="handleChange"
/>
</el-form-item>
</section>
<el-form-item label="工单描述:">
<el-input
v-model="form.gdms"
:rows="2"
type="textarea"
placeholder="请填写"
/>
</el-form-item>
</el-form>
<template #footer>
<div class="dialog-footer">
<section v-if="id">
<el-button @click="handlerRetreat()">退单</el-button>
<el-button type="primary" @click="confirm()">上报待处置</el-button>
<el-button type="primary" @click="handleFeedBack()"
>处理反馈</el-button
>
</section>
<section v-else>
<el-button @click="handlerClose()">取消</el-button>
<el-button type="primary" @click="confirm()">确定</el-button>
</section>
</div>
</template>
<!-- 退单 -->
<chargeBack v-model="retreat" :id="id" @confirm="handlerClose"></chargeBack>
<!-- -->
<feedBack v-model="feedBackView" :id="id" @confirm="handlerClose" />
</el-dialog>
</template>
<script setup>
import { addyj, updateyj, intruderyj, getyjById } from "@/api/emergency";
import { chargeBack, feedBack } from "../index";
import MarsMap from "@/components/mars-work/mars-map.vue";
import mapOptions from "@/components/mars-work/mapOptions";
import markerIcon from "@/assets/images/map-marker.png";
import { gaodeAddress, gaodePOI } from "@/utils/common.js";
const { proxy } = getCurrentInstance();
const gaodePOIList = ref([]);
const currentId = ref(0);
const cascaderProps = {
value: "deptId",
label: "deptName",
};
const props = defineProps({
title: {
type: String,
default: "",
},
dict: {
type: Object,
default: {
gdlx: [],
gdlevel: [],
clfa: [],
gdms: [],
deptList: [],
},
},
id: {
type: Number,
},
modelValue: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["update:modelValue", "confirm"]);
//地图配置
const configUrl = "lib/config/config.json";
let mapData = null;
let mapLayer = {};
let entity = null;
const data = reactive({
form: {
id: null,
address: undefined, //地址
clbz: undefined, //处理班组
clfa: undefined, //处理方案
clhtp: undefined, //处理后图片
clms: undefined, //处理描述
createBy: undefined, //创建人
createId: undefined, //创建者id
createTime: undefined, //创建时间
deptId: undefined, //部门id
gdLevel: undefined, //工单等级
gdType: undefined, //工单类型
gdms: undefined, //工单描述
gdtp: undefined, //工单图片
lat: undefined, //纬度
lon: undefined, //经度
pqcl: undefined, //派遣车辆
pqrs: undefined, //派遣人数
reason: undefined, //退单原因
status: undefined, //状态 0:待勘察1:待派发,2:已退单.3:待处理,4:已完成
zzjg: undefined,
xdsqm: undefined, //行道树/乔木
yxlx: undefined, //影响类型
},
rules: {
address: [{ required: true, message: "请填写工单地址", trigger: "blur" }],
gdType: [{ required: true, message: "请选择工单类型", trigger: "blur" }],
xdsqm: [{ required: true, message: "请选择", trigger: "blur" }],
zzjg: [{ required: true, message: "请选择选派班组", trigger: "blur" }],
gdtp: [{ required: true, message: "请上传工单照片", trigger: "blur" }],
yxlx: [{ required: true, message: "请选择影响类型", trigger: "blur" }],
},
});
const { form, rules } = toRefs(data);
const visible = ref(props.modelValue);
const retreat = ref(false);
const feedBackView = ref(false);
// 监听外部 modelValue 变化
watch(
() => props.modelValue,
(val) => {
visible.value = val;
}
);
watch(visible, (val) => {
emit("update:modelValue", val);
});
const changeType = () => {
if (props.id) form.value.xdsqm = undefined;
};
/**
* 处理反馈
*
*/
const handleFeedBack = () => {
confirm(false);
};
/**
* 退单
*
*/
const handlerRetreat = () => {
retreat.value = true;
};
/**
* 提交
*/
const confirm = (isConfirm = true) => {
proxy.$refs["formRef"].validate(async (valid) => {
if (valid) {
if (!form.value.lat || !form.value.lon) {
proxy.$modal.msgWarning("请先落点至地图上!");
return;
}
if (form.value.id) {
form.value.yxlx = filterArray(form.value.yxlx, "join");
await intruderyj(form.value);
proxy.$modal.msgSuccess(`${props.title}成功`);
} else {
form.value.zzjg = filterArray(form.value.zzjg, "join");
await addyj(form.value);
proxy.$modal.msgSuccess("新增成功");
}
if (isConfirm) {
handlerClose(isConfirm);
} else {
feedBackView.value = true;
form.value.yxlx = filterArray(form.value.yxlx);
}
}
});
};
/**
* 获取详情
*/
const getInfo = async (val) => {
if (!props.id || !visible.value) return;
const res = await getyjById(props.id);
if (props.id) {
res.data.yxlx = filterArray(res.data.yxlx);
} else {
res.data.zzjg = res.data.zzjg.split(",").map((item) => parseInt(item));
}
form.value = res.data;
if (form.value.lat && form.value.lon && mapData) {
nextTick(() => {
handleMapClick(form.value.lat, form.value.lon);
mapData.flyToGraphic(mapLayer.marker, { radius: 300 });
});
}
};
const filterArray = (data, type) => {
if (!type) {
if (data) {
return data.split(",");
} else {
return [];
}
} else {
if (data) {
return data.join();
} else {
return "";
}
}
};
/**
*
*/
const handlerClose = (isConfirm) => {
if (isConfirm) {
emit("confirm");
}
visible.value = false;
proxy.resetForm("formRef");
gaodePOIList.value = [];
if (mapData) {
mapData.destroy();
mapData = null;
mapLayer.marker?.clear();
entity = null;
}
};
/**
* 地址搜索
*/
const handleSearch = async () => {
if (!form.value.address) {
proxy.$modal.msgWarning("请输入关键字");
return;
}
const res = await gaodePOI(form.value.address);
gaodePOIList.value = res;
};
/**
* 结果上图
* @param item
*/
const handleCograph = (item) => {
if (currentId.value != item.id) {
const point = item.location.split(",");
handleMapClick(parseFloat(point[0]), parseFloat(point[1]));
mapData.flyToGraphic(mapLayer.marker, { radius: 300 });
currentId.value = item.id;
form.value.address = item.name;
}
};
/**
* 级联取人员deptID
*/
const handleChange = (value) => {
form.value.deptId = value[value.length - 1];
};
/**
* 获取地图配置
*/
const getMapOptions = computed(() => {
mapOptions.scene.sceneMode = 2;
mapOptions.basemaps[0] = {
pid: 10,
name: "高德电子",
type: "gaode",
icon: "//data.mars3d.cn/img/thumbnail/basemap/gaode_vec.png",
layer: "vec",
show: true,
};
return mapOptions;
});
/**
* 地图初始化成功
* @param map
*/
const marsOnload = (map) => {
mapData = map;
mapLayer.marker = new mars3d.layer.GraphicLayer({
allowDrillPick: true,
});
mapData.addLayer(mapLayer.marker);
map.on(mars3d.EventType.click, async ({ cartesian }) => {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
const longitude = Cesium.Math.toDegrees(cartographic.longitude);
const latitude = Cesium.Math.toDegrees(cartographic.latitude);
const res = await gaodeAddress(`${longitude},${latitude}`);
form.value.address = res.formatted_address;
handleMapClick(longitude, latitude);
});
getInfo();
};
/**
* @description: 处理地图点击
* @private
* @param {number} longitude 经度
* @param {number} latitude 纬度
* @returns
*/
const handleMapClick = (longitude, latitude) => {
if (!isPositiveDecimal(longitude)) longitude = parseFloat(longitude);
if (!isPositiveDecimal(latitude)) latitude = parseFloat(latitude);
if (entity) {
entity.position = [longitude, latitude];
} else {
entity = new mars3d.graphic.BillboardEntity({
position: [longitude, latitude],
style: {
image: markerIcon,
width: 35,
height: 36,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
},
});
mapLayer.marker?.addGraphic(entity);
}
form.value.lat = longitude; //纬度
form.value.lon = latitude; //经度
};
const isPositiveDecimal = (num) => {
return typeof num === "number" && num >= 0 && !Number.isInteger(num);
};
</script>
<style lang="scss" scoped>
.map {
height: 400px;
width: 100%;
border: 1px solid #ccc;
margin-bottom: 15px;
}
.map-gps {
height: 25px;
width: 25px;
}
.serch-list {
width: 100%;
min-height: 50px;
max-height: 250px;
overflow-y: auto;
border: 1px solid #ccc;
& > div {
cursor: pointer;
padding: 3px 10px;
font-size: 14px;
}
& > div:hover,
.activeitem {
background-color: #4776eb;
color: white;
font-weight: bold;
}
}
.location-search {
font-size: 14px;
cursor: pointer;
}
</style>