suerprisePlus
2024-08-21 7d57b0fef0f220dfe7c868ce1113a7ce6eb6c468
添加本地矢量地图服务,初始化视角切换
已修改14个文件
799 ■■■■ 文件已修改
public/config/config.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/App.vue 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/mapView/peiwang.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/mapSdk/index.js 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/mapSdk/mapConfig.js 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/mapSdk/mapData.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/js/mapSdk/mapServe.js 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/RuoYi/Msgger/index.vue 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mapOl/index.vue 101 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManager/equipMante/AddOrUpdate.vue 257 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/dataManager/equipMante/index.vue 69 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/index.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/leftMenu.vue 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/visualization/rightMenu.vue 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/config/config.js
@@ -32,15 +32,18 @@
  ragServices: "http://" + ragHost+ "/api/vi",
  imageUrl: "",
  // sdk显示
  sdkImg: host + "/visual/CimSDK/",
  sdkImg: host + "/CimSDK/",
  // 天地图
  tdToken: "94a34772eb88317fcbf8428e10448561",
  // geoServer服务
  geoServer: {
    url: "http://" + geoHost + "/geoserver/sxpw",
    wms: "/wms",
    wfs: ""
    wfs: "",
    layers:["sxpw:sxdwx","sxpw:tygdtif17"]
  },
  pySocket:"ws://192.168.11.24:8101/peiwang/ws/asset",
  //地下数据
  terrain: {
    isShow: false,
src/App.vue
@@ -21,6 +21,17 @@
                return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
            }
        }
  },
  data() {
    return {
    }
  },
  mounted() {
  },
  methods: {
    }
};
</script>
src/api/mapView/peiwang.js
@@ -248,9 +248,9 @@
    //请求地址
    return peiWangServer.post('/peiwang/tokeninfo/update', params);
}
export function faultreport_list(params) {
export function faultreport_query(params) {
    //请求地址
    return peiWangServer.get('/peiwang/faultreport/list', { params: params });
    return peiWangServer.get('/peiwang/faultreport/query', { params: params });
}
export function faultreport_save(params) {
    //请求地址
@@ -260,3 +260,7 @@
    //请求地址
    return peiWangServer.post('/peiwang/faultreport/update', params);
}
export function faultreport_delete(params) {
    //请求地址
    return peiWangServer.post('/peiwang/faultreport/delete', params);
}
src/assets/js/mapSdk/index.js
@@ -2,6 +2,7 @@
import mapData from './mapData';
import mapServer from './mapServe';
import * as turf from '@turf/turf';
import store from '@/store';
const mapInit = {
    async Init() {
        window.earthCtrl = new SmartEarth.EarthCtrl('sdkContainer', {
@@ -18,6 +19,7 @@
        window.Viewer = earthCtrl.viewer;
        //设置地球颜色
        Viewer.scene.globe.baseColor = Cesium.Color.fromCssColorString('#A9A9A9');
        Viewer.imageryLayers.removeAll()
        // 地形加载
        const terrain = config.terrain;
        if (terrain.isShow && terrain.isUrl) {
@@ -28,31 +30,58 @@
            Viewer.terrainProvider = terrainProvider;
        }
        // Viewer.scene.screenSpaceCameraController.maximumZoomDistance =50000
        // 默认设置底图
        this.addImageLayer();
        // 添加鼠标点击事件
        this.addMapClick();
    },
    addImageLayer() {
        const baseLayer = mapData.baseLayer;
        // 添加天地图底图
        mapServer.addLayer({
            serveType: 'tdMap',
            url: baseLayer.sUrl + baseLayer.vecLayer + baseLayer.lUrl,
        });
        // mapServer.addLayer({
        //     serveType: 'WMS',
        //     url: 'sxpw:shanxitif',
        //     serveType: 'tdMap',
        //     url: baseLayer.sUrl + baseLayer.vecLayer + baseLayer.lUrl,
        // });
        // 添加天地图标注
        mapServer.addLayer({
            serveType: 'tdMap',
            url: baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl,
            serveType: 'WMS',
            url: config.geoServer.layers[1],
        });
        // 添加天地图标注
        // mapServer.addLayer({
        //     serveType: 'tdMap',
        //     url: baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl,
        // });
        // 初始化视角
        this.setdefaultPerspective();
    },
    setdefaultPerspective() {
        mapConfig.sertCameraTo(mapData.defaultPerspective);
    },
    addMapClick() {
        // 为viewer添加鼠标点击事件监听
        Viewer.screenSpaceEventHandler.setInputAction((event) => {
            // 获取点击位置的世界坐标
            var pickedFeature = Viewer.scene.pick(event.position);
            if (Cesium.defined(pickedFeature)) {
                console.log(pickedFeature);
                if (pickedFeature.id) {
                    const obj = pickedFeature.id;
                    var arr=[];
                    for(var key in obj){
                        arr.push({
                            name: key,
                            val: obj[key],
                        });
                        store.dispatch('mapLayers/changeMapInfo', []);
                        if (arr.length > 0) {
                            store.dispatch('mapLayers/changeMapInfo', arr);
                        }
                    }
                }
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    },
};
export default mapInit;
src/assets/js/mapSdk/mapConfig.js
@@ -7,29 +7,31 @@
                y: res.y,
                z: res.z,
            },
            orientation: {
                heading:res.heading,
                pitch: res.pitch,
                roll: res.roll,
            },
        });
    },
    userSceneFlyTo(res){
        const options = {
            duration: 2,
            offset: new SmartEarth.Cesium.HeadingPitchRange(1.0, -0.3, 1000)
            offset: new SmartEarth.Cesium.HeadingPitchRange(1.0, -0.3, 1000),
        };
        earthCtrl.userScene.flyTo(res,options);
    },
    getModelMatrix(res) {
        var headingPitchRoll = new Cesium.HeadingPitchRoll(res.heading, res.pitch, res.roll);
        var position = Cesium.Cartesian3.fromDegrees(res.longitude, res.latitude, res.altitude);
        var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(
            position, headingPitchRoll, Cesium.Ellipsoid.WGS84,
            Cesium.Transforms.eastNorthUpToFixedFrame,
            new Cesium.Matrix4());
        var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, headingPitchRoll, Cesium.Ellipsoid.WGS84, Cesium.Transforms.eastNorthUpToFixedFrame, new Cesium.Matrix4());
        return modelMatrix;
    },
    getWKTParse(res){
        return WKT.parse(res)
        return WKT.parse(res);
    },
    getWKTConvert(res){
        return WKT.convert(res)
    }
        return WKT.convert(res);
    },
};
export default mapConfig;
src/assets/js/mapSdk/mapData.js
@@ -208,9 +208,12 @@
    // 默认视角
    defaultPerspective: {
        x: -1936842.4744685106,
        y: 4665314.067108395,
        z: 3898603.230008434,
        x: -1934358.744458335,
        y: 4659454.007273499,
        z: 3890986.719081069,
        heading: 0.3383482086332279, // 方向
        pitch: -0.4301190518998017, // 倾斜角度
        roll: 6.283178115297752,
    },
    // 图层管理
    layerData: {
src/assets/js/mapSdk/mapServe.js
@@ -70,7 +70,7 @@
            const url = '/glb/' + item.type + '.glb';
            modelLayer.add(
                Cesium.Model.fromGltf({
                    id: item.id,
                    id: item,
                    url: url,
                    scale: 1,
                    minimumPixelSize: 20,
@@ -94,7 +94,7 @@
        const url = '/glb/' + item.type + '.glb';
        modelLayer.add(
            Cesium.Model.fromGltf({
                id: item.id,
                id: item,
                url: url,
                scale: 1,
                minimumPixelSize: 20,
src/components/RuoYi/Msgger/index.vue
@@ -1,32 +1,116 @@
<template>
    <div class="msgBox" @click="setShowMenuClick">
    <div class="msgBox" @click.stop="setShowMenuClick(true)">
        <i style="font-size: 20px;" class="el-icon-chat-line-round"></i>
        <el-badge v-show="msgCount > 0" :value="msgCount" class="item">
        </el-badge>
        <el-dialog title="异常信息" :visible.sync="dialogVisible" width="30%" :show-close="false">
            <el-table :data="msgData" style="width: 100%">
                <el-table-column prop="msg" label="设备名称">
                </el-table-column>
                <el-table-column prop="point" label="设备位置">
                </el-table-column>
                <el-table-column label="操作" width="100">
                    <template slot-scope="scope">
                        <el-button @click="handleClick(scope.row)" type="text" size="small">查看</el-button>
                        <el-button @click="handleClick2(scope.row)" type="text" size="small">分发</el-button></el-button>
                    </template>
                </el-table-column>
            </el-table>
            <span slot="footer" class="dialog-footer">
                <el-button @click.stop="dialogVisible = false">关 闭</el-button>
            </span>
            <el-dialog width="30%" title="位置" :visible.sync="innerVisible" append-to-body>
                <div style="height: 540px">
                    <olMap v-if="innerVisible" :parentData="parentData"></olMap>
                </div>
            </el-dialog>
        </el-dialog>
    </div>
</template>
<script>
import olMap from '@/components/mapOl/index.vue';
export default {
    name: 'RouYiMsg',
    components: {
        olMap
    },
    data() {
        return {
            msgCount: 0,
            dialogVisible: false
            msgCount: 1,
            dialogVisible: false,
            dialogFlag: false,
            wsSocket: null,
            innerVisible: false,
            msgData: [{
                msg: "变压器故障",
                point: "POINT (112.56978672907 37.8558881392881)"
            }],
            parentData: null,
        }
    },
    methods: {
        setShowMenuClick() {
        handleClick2(row) {
            this.$message({
                showClose: true,
                message: '已分发到相关负责人',
                type: 'success'
            });
        },
        handleClick(row) {
            const obj = {
                val: row,
                type: 'point',
                isShow: false,
            }
            this.parentData = JSON.stringify([obj])
            this.innerVisible = true
        },
        setShowMenuClick(res) {
            this.dialogVisible = true
        },
        handleClose() {
            this.dialogVisible = false
        },
        createSocket() {
            this.wsSocket = new WebSocket(config.pySocket);
            this.wsSocket.onopen = (event) => {
                console.log('WebSocket连接成功');
            };
            this.wsSocket.onmessage = (event) => {
                if (event.data != "连接成功") {
                    const obj = JSON.parse(event.data);
                    if (obj.mes) {
                        this.setShowMsg(obj)
        }
                }
                // 处理接收到的消息
            };
        },
        setShowMsg(res) {
            const filter = this.msgData.filter(item => {
                if (item.msg == res.msg && item.point == res.point) {
                    return item;
                }
            })
            if (filter.length > 0) return;
            this.msgData.push(res)
            this.msgCount = this.msgData.length;
        },
    },
    mounted() {
        console.log(123);
        if (!this.wsSocket) {
            this.createSocket();
        }
    },
}
src/components/mapOl/index.vue
@@ -8,7 +8,7 @@
                <el-form-item label="纬度:">
                    {{ formInline.lat }}
                </el-form-item>
                <el-form-item>
                <el-form-item v-show="isShow">
                    <el-button type="success" icon="el-icon-plus" @click="drowPoint"></el-button>
                    <el-button type="danger" icon="el-icon-delete" @click="clearDrawPoint"></el-button>
                </el-form-item>
@@ -34,6 +34,7 @@
import mapData from '@/assets/js/mapSdk/mapData.js';
import mapConfig from '../../assets/js/mapSdk/mapConfig';
import * as turf from '@turf/turf'
import LineString from 'ol/geom/LineString';
export default {
    props: {
        parentData: {
@@ -44,6 +45,7 @@
    },
    data() {
        return {
            isShow: true,
            mapol: null,
            drawLayer: null,
            formInline: {
@@ -59,17 +61,31 @@
        initOlMap() {
            const baseLayer = mapData.baseLayer;
            const vecUrl = baseLayer.sUrl + baseLayer.vecLayer + baseLayer.lUrl
            var vectorLayer = new TileLayer({
                source: new XYZ({
                    url: vecUrl + config.tdToken,
            const geo= config.geoServer;
            // var vectorLayer = new TileLayer({
            //     source: new XYZ({
            //         url: vecUrl + config.tdToken,
            //     }),
            // });
            // const cvaUrl = baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl
            // var vectorLayer1 = new TileLayer({
            //     source: new XYZ({
            //         url: cvaUrl + config.tdToken,
            //     }),
            // });
            var layer2 = new Image({
                name: "Wms_Layer",
                source: new ImageWMS({
                    crossOrigin: "anonymous",
                    url: geo.url + geo.wms,
                    params: {
                        FORMAT: "image/png",
                        VERSION: "1.1.1",
                        LAYERS: geo.layers[0],
                    },
                }),
            });
            const cvaUrl = baseLayer.sUrl + baseLayer.cvaLayer + baseLayer.lUrl
            var vectorLayer1 = new TileLayer({
                source: new XYZ({
                    url: cvaUrl + config.tdToken,
                }),
            });
            this.mapol.addLayer(layer2);
            this.mapol = new Map({
                target: 'mapView',
                layers: [vectorLayer, vectorLayer1],
@@ -85,16 +101,38 @@
                name: "Wms_Layer",
                source: new ImageWMS({
                    crossOrigin: "anonymous",
                    url: config.geoServer.url + config.geoServer.wms,
                    url: geo.url + geo.wms,
                    params: {
                        FORMAT: "image/png",
                        VERSION: "1.1.1",
                        LAYERS: 'sxpw:sxdwx',
                        LAYERS: geo.layers[1],
                    },
                }),
            });
            this.mapol.addLayer(layer2);
            if (this.parentData) {
                if (this.parentData.indexOf('type') > -1) {
                    const data = JSON.parse(this.parentData)[0];
                    this.isShow = data.isShow
                    if (data.type == 'point') {
                        const obj = mapConfig.getWKTParse(data.val.point)
                        this.formInline = {
                            lon: obj.coordinates[0],
                            lat: obj.coordinates[1],
                        }
                        this.addPointData(obj);
                    } else if (data.type == 'line') {
                        const obj = mapConfig.getWKTParse(data.val.f_location)
                        this.formInline = {
                            lon: obj.coordinates[0],
                            lat: obj.coordinates[1],
                        }
                        this.addPointData(obj);
                        const line = mapConfig.getWKTParse(data.val.re_position)
                        this.addLineData(line)
                    }
                } else {
                const obj = mapConfig.getWKTParse(this.parentData)
                this.formInline = {
                    lon: obj.coordinates[0],
@@ -102,6 +140,45 @@
                }
                this.addPointData(obj);
            }
            }
        },
        addLineData(res) {
            var coord = res.coordinates;
            var geom = [];
            coord.filter(i => {
                geom.push(transform(
                    i,
                    'EPSG:4326',
                    'EPSG:3857'
                ))
            })
            var feature = new Feature({
                type: 'LineString',
                geometry: new LineString(geom),
            });
            feature.setStyle(
                new Style({
                    stroke: new Stroke({
                        color: 'blue',
                        width: 3,
                    }),
                })
            );
            const extent = feature.getGeometry().getExtent()
            var source = new VectorSource();
            source.addFeature(feature);
            // 创建线的矢量图层
            var vectorLayer = new VectorLayer();
            vectorLayer.setSource(source);
            this.mapol.addLayer(vectorLayer);
            this.mapol.getView().fit(extent, {
                size: this.mapol.getSize(),
                padding: [100, 100,200,100], // 四个方向的边距,可选
                constrainResolution: false, // 是否限制分辨率,可选
            });
        },
        addPointData(res) {
            const coord = res.coordinates;
src/views/dataManager/equipMante/AddOrUpdate.vue
@@ -1,55 +1,68 @@
<template>
    <el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
    <el-dialog  :before-close="closeHandler" :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
        <el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()"
            label-width="120px">
            <el-form-item label="客户名称" prop="cName">
                <el-input v-model="dataForm.cName" placeholder="客户名称"></el-input>
            <el-form-item label="客户名称" prop="c_name">
                <el-input v-model="dataForm.c_name" placeholder="客户名称"></el-input>
            </el-form-item>
            <el-form-item label="故障地点名称" prop="fName">
                <el-input v-model="dataForm.fName" placeholder="故障地点名称"></el-input>
            <el-form-item label="故障地点名称" prop="f_name">
                <el-input v-model="dataForm.f_name" placeholder="故障地点名称"></el-input>
            </el-form-item>
            <el-form-item label="故障地点经纬度" prop="fLocation">
                <el-input v-model="dataForm.fLocation" placeholder="故障地点经纬度"></el-input>
            <el-form-item label="故障地点经纬度" prop="f_location">
                <el-input v-model="dataForm.f_location" placeholder="故障地点经纬度"></el-input>
            </el-form-item>
            <el-form-item label="联系电话" prop="fPhone">
                <el-input v-model="dataForm.fPhone" placeholder="联系电话"></el-input>
            <el-form-item label="联系电话" prop="f_phone">
                <el-input v-model="dataForm.f_phone" placeholder="联系电话"></el-input>
            </el-form-item>
            <el-form-item label="故障时间" prop="fDate">
                <el-input v-model="dataForm.fDate" placeholder="故障时间"></el-input>
            <el-form-item label="故障时间" prop="f_date">
                <el-date-picker style="width:100%" @change="handleDateChange" v-model="dataForm.f_date" type="datetime"
                    placeholder="选择故障时间">
                </el-date-picker>
                <!-- <el-input v-model="dataForm.f_date" placeholder="故障时间"></el-input> -->
            </el-form-item>
            <el-form-item label="报修方式" prop="fType">
                <el-input v-model="dataForm.fType" placeholder="报修方式"></el-input>
            <el-form-item label="报修方式" prop="f_type">
                <el-input v-model="dataForm.f_type" placeholder="报修方式"></el-input>
            </el-form-item>
            <el-form-item label="记录人" prop="fMan">
                <el-input v-model="dataForm.fMan" placeholder="记录人"></el-input>
            <el-form-item label="记录人" prop="f_man">
                <el-input v-model="dataForm.f_man" placeholder="记录人"></el-input>
            </el-form-item>
            <el-form-item label="报修内容" prop="fContent">
                <el-input v-model="dataForm.fContent" placeholder="报修内容"></el-input>
            <el-form-item label="报修内容" prop="f_content">
                <el-input v-model="dataForm.f_content" placeholder="报修内容"></el-input>
            </el-form-item>
            <el-form-item label="到达现场时间" prop="rDate">
                <el-input v-model="dataForm.rDate" placeholder="到达现场时间"></el-input>
            <el-form-item label="到达现场时间" prop="r_date">
                <!-- <el-input v-model="dataForm.r_date" placeholder="到达现场时间"></el-input> -->
                <el-date-picker style="width:100%" @change="handleDateChange" v-model="dataForm.r_date" type="datetime"
                    placeholder="选择达现场时间">
                </el-date-picker>
            </el-form-item>
            <el-form-item label="维修结束时间" prop="reDate">
                <el-input v-model="dataForm.reDate" placeholder="维修结束时间"></el-input>
            <el-form-item label="维修结束时间" prop="re_date">
                <!-- <el-input v-model="dataForm.re_date" placeholder="维修结束时间"></el-input> -->
                <el-date-picker style="width:100%" @change="handleDateChange" v-model="dataForm.re_date" type="datetime"
                    placeholder="选择维修结束时间">
                </el-date-picker>
            </el-form-item>
            <el-form-item label="维修轨迹" prop="rePosition">
                <el-input v-model="dataForm.rePosition" placeholder="维修轨迹"></el-input>
            <el-form-item label="维修轨迹" prop="re_position">
                <el-input v-model="dataForm.re_position" placeholder="维修轨迹"></el-input>
            </el-form-item>
            <el-form-item label="维修视频" prop="reVideo">
                <el-input v-model="dataForm.reVideo" placeholder="维修视频"></el-input>
            <el-form-item label="维修视频" prop="re_video">
                <el-input v-model="dataForm.re_video" placeholder="维修视频"></el-input>
            </el-form-item>
            <el-form-item label="客户评价" prop="reEvaluation">
                <el-input v-model="dataForm.reEvaluation" placeholder="客户评价"></el-input>
            <el-form-item label="客户评价" prop="re_evaluation">
                <el-input v-model="dataForm.re_evaluation" placeholder="客户评价"></el-input>
            </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
            <el-button @click="visible = false">取消</el-button>
            <el-button @click="closeHandler">取消</el-button>
            <el-button type="primary" @click="dataFormSubmit()">确定</el-button>
        </span>
    </el-dialog>
</template>
<script>
// POINT (112.56978672907 37.8558881392881)
// LINESTRING (112.56610139210423 37.87199523758289, 112.56777608401627 37.87190547038274, 112.56775238085118 37.862274562096125, 112.56829544919117 37.862166910066264, 112.56829523145755 37.85994297223096, 112.56836294214209 37.858185324275034, 112.56874759228823 37.858023871243766, 112.56890584253452 37.85671457963388, 112.57008241825407 37.85633780011934, 112.56994660283333 37.85596117981906)
import { faultreport_save, faultreport_update } from '@/api/mapView/peiwang.js';
export default {
    data() {
@@ -57,68 +70,123 @@
            visible: false,
            dataForm: {
                id: undefined,
                cName: '',
                fName: '',
                fLocation: '',
                fPhone: '',
                fDate: '',
                fType: '',
                fMan: '',
                fContent: '',
                rDate: '',
                reDate: '',
                rePosition: '',
                reVideo: '',
                reEvaluation: ''
                c_name: '',
                f_name: '',
                f_location: '',
                f_phone: '',
                f_date: '',
                f_type: '',
                f_man: '',
                f_content: '',
                r_date: '',
                re_date: '',
                re_position: '',
                re_video: '',
                re_evaluation: ''
            },
            objData: null,
            dataRule: {
                cName: [
                c_name: [
                    { required: true, message: '客户名称不能为空', trigger: 'blur' }
                ],
                fName: [
                f_name: [
                    { required: true, message: '故障地点名称不能为空', trigger: 'blur' }
                ],
                fLocation: [
                f_location: [
                    { required: true, message: '故障地点经纬度不能为空', trigger: 'blur' }
                ],
                fPhone: [
                f_phone: [
                    { required: true, message: '联系电话不能为空', trigger: 'blur' }
                ],
                fDate: [
                f_date: [
                    { required: true, message: '故障时间不能为空', trigger: 'blur' }
                ],
                fType: [
                f_type: [
                    { required: true, message: '报修方式不能为空', trigger: 'blur' }
                ],
                fMan: [
                f_man: [
                    { required: true, message: '记录人不能为空', trigger: 'blur' }
                ],
                fContent: [
                f_content: [
                    { required: true, message: '报修内容不能为空', trigger: 'blur' }
                ],
                rDate: [
                r_date: [
                    { required: true, message: '到达现场时间不能为空', trigger: 'blur' }
                ],
                reDate: [
                re_date: [
                    { required: true, message: '维修结束时间不能为空', trigger: 'blur' }
                ],
                rePosition: [
                re_position: [
                    { required: true, message: '维修轨迹不能为空', trigger: 'blur' }
                ],
                reVideo: [
                    { required: true, message: '维修视频不能为空', trigger: 'blur' }
                ],
                reEvaluation: [
                    { required: true, message: '客户评价不能为空', trigger: 'blur' }
                ]
            }
        }
    },
    methods: {
        handleDateChange(value, picker) {
            return this.getNowTime(value)
        },
        getNowTime(res) {
            var now = null;
            if (res) {
                now = new Date(res);
            } else {
                now = new Date();
            }
            const year = now.getFullYear();
            const month = now.getMonth() + 1; // 月份是从0开始的
            const day = now.getDate();
            const hours = now.getHours();
            const minutes = now.getMinutes();
            const seconds = now.getSeconds();
            // 格式化月份和日期,保持两位数
            const formattedMonth = month < 10 ? '0' + month : month;
            const formattedDay = day < 10 ? '0' + day : day;
            const formattedHours = hours < 10 ? '0' + hours : hours;
            const formattedMinutes = minutes < 10 ? '0' + minutes : minutes;
            const formattedSeconds = seconds < 10 ? '0' + seconds : seconds;
            return `${year}-${formattedMonth}-${formattedDay} ${formattedHours}:${formattedMinutes}:${formattedSeconds}`;
        },
        init(response) {
            this.visible = true
            this.objData = null
            this.dataForm = {
                id: undefined,
                c_name: '',
                f_name: '',
                f_location: '',
                f_phone: '',
                f_date: this.getNowTime(),
                f_type: '',
                f_man: '',
                f_content: '',
                r_date: this.getNowTime(),
                re_date: this.getNowTime(),
                re_position: '',
                re_video: '',
                re_evaluation: ''
            }
            if (response) {
                this.dataForm = { ...response }
                this.objData = { ...response }
                this.dataForm = {
                    id: this.objData.id,
                    c_name: this.objData.c_name,
                    f_name: this.objData.f_name,
                    f_location: this.objData.f_location,
                    f_phone: this.objData.f_phone,
                    f_date: this.objData.f_date,
                    f_type: this.objData.f_type,
                    f_man: this.objData.f_man,
                    f_content: this.objData.f_content,
                    r_date: this.objData.r_date,
                    re_date: this.objData.re_date,
                    re_position: this.objData.re_position,
                    re_video: this.objData.re_video,
                    re_evaluation: this.objData.re_evaluation
                }
            }
        },
@@ -127,32 +195,75 @@
            this.$refs['dataForm'].validate((valid) => {
                if (valid) {
                    if (this.dataForm.id) {
                        this.setEditReport();
                        this.setEditReport(valid);
                    } else {
                        this.setSaveReport();
                    }
                }
            })
        },
        formateDate(res) {
            if (typeof res == 'string') return res;
            return this.getNowTime(res)
        },
        closeHandler(){
            this.visible = false
            this.$emit('refreshDataList')
        },
        setSaveReport() {
            faultreport_save(this.dataForm).then(response => {
                console.log(response);
                // this.$message({
                //   message: '操作成功',
                //   type: 'success',
                //   duration: 1500,
                //   onClose: () => {
                //     this.visible = false
                //     this.$emit('refreshDataList')
                //   }
                // })
            const obj = { ...this.dataForm }
            obj.f_date = this.formateDate(obj.f_date)
            obj.r_date = this.formateDate(obj.r_date)
            obj.re_date = this.formateDate(obj.re_date)
            faultreport_save(obj).then(response => {
                 this.closeHandler();
                if (response.data.msg == 'success') {
                    this.$message({
                        message: '操作成功',
                        type: 'success',
                        duration: 1000,
                    })
                } else {
                    this.$message({
                        message: '操作失败',
                        type: 'warning',
                        duration: 1000,
                    })
                }
            })
        },
        setEditReport() {
            faultreport_update(this.dataForm).then(response => {
                console.log(response);
            const obj = { ...this.dataForm }
            obj.f_date = this.formateDate(obj.f_date)
            obj.r_date = this.formateDate(obj.r_date)
            obj.re_date = this.formateDate(obj.re_date)
            faultreport_update(obj).then(response => {
                 this.closeHandler();
                if (response.data.msg == 'success') {
                    this.$message({
                        message: '操作成功',
                        type: 'success',
                        duration: 1000,
            })
                } else {
                    this.$message({
                        message: '操作失败',
                        type: 'warning',
                        duration: 1000,
                    })
                }
            })
        },
src/views/dataManager/equipMante/index.vue
@@ -11,7 +11,7 @@
                <div>
                    <el-button plain size="small" @click="getDataList()">查询</el-button>
                    <el-button plain size="small" type="primary" @click="addOrUpdateHandle()">新增</el-button>
                    <el-button plain size="small" type="danger"
                    <el-button plain size="small" @click="deleteHandleList" type="danger"
                        :disabled="dataListSelections.length <= 0">批量删除</el-button>
                </div>
            </div>
@@ -53,8 +53,9 @@
                    </el-table-column>
                    <el-table-column fixed="right" header-align="center" align="center" width="150" label="操作">
                        <template slot-scope="scope">
                            <el-button type="text" size="small">修改</el-button>
                            <el-button type="text" size="small">删除</el-button>
                            <el-button type="text" size="small" @click="addOrUpdateHandle(scope.row)">修改</el-button>
                            <el-button type="text" size="small" @click="deleteHandleRow(scope.row)">删除</el-button>
                            <el-button type="text" size="small" @click="showHandleRow(scope.row)">预览</el-button>
                        </template>
                    </el-table-column>
                </el-table>
@@ -64,16 +65,23 @@
        </el-card>
        <!-- 弹窗, 新增 / 修改 -->
        <add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
        <el-dialog width="30%" :title="showTitle" :visible.sync="innerVisible" append-to-body>
            <div style="height: 540px">
                <olMap v-if="innerVisible" :parentData="parentData"></olMap>
            </div>
        </el-dialog>
    </div>
</template>
<script>
import { faultreport_list } from '@/api/mapView/peiwang.js';
import { faultreport_query, faultreport_delete } from '@/api/mapView/peiwang.js';
import AddOrUpdate from './AddOrUpdate.vue';
import olMap from '@/components/mapOl/index.vue';
export default {
    name: "equipMante",
    components: {
        AddOrUpdate
        AddOrUpdate,
        olMap
    },
    data() {
        return {
@@ -91,27 +99,43 @@
            dataList: [],
            total: 0,
            addOrUpdateVisible: false,
            showData: null,
            innerVisible: false,
            parentData: null,
            showTitle:null,
        }
    },
    mounted() {
        this.getDataList();
    },
    methods: {
        showHandleRow(row) {
            this.showData = { ...row }
            const obj = {
                val: this.showData,
                type: 'line',
                isShow: false,
            }
            this.showTitle= row['c_name']
            this.parentData = JSON.stringify([obj])
            this.innerVisible = true;
        },
        addOrUpdateHandle(res) {
            this.addOrUpdateVisible = true
            this.$nextTick(() => {
                   this.$refs.addOrUpdate.init(res)
            })
        },
        selectionChangeHandle(res) {
            this.dataListSelections = res;
        },
        getDataList() {
            this.dataListLoading = true;
            faultreport_list({
            faultreport_query({
                page: this.queryParams.pageIndex,
                limit: this.queryParams.pageSize,
                key: this.queryParams.name,
                c_name: this.dataForm.key,
            }).then(response => {
                this.dataListLoading = false;
                if (response.status != 200) return
@@ -119,8 +143,39 @@
                this.total = obj.totalCount;
                this.dataList = obj.list;
            })
        },
        deleteHandleRow(res) {
            this.deleteHandle([res.id])
        },
        deleteHandleList() {
            var ids = this.dataListSelections.map(item => {
                return item.id
            })
            this.deleteHandle(ids)
        },
        deleteHandle(res) {
            faultreport_delete(res).then(response => {
                if (response.data.msg == 'success') {
                    this.$message({
                        message: '操作成功',
                        type: 'success',
                        duration: 1000,
                    })
                } else {
                    this.$message({
                        message: '操作失败',
                        type: 'warning',
                        duration: 1000,
                    })
        }
                this.getDataList();
            })
    }
    },
}
</script>
src/views/visualization/index.vue
@@ -3,10 +3,10 @@
        <div class="title"></div>
        <mapView></mapView>
        <div class="leftMenu">
            <left-menu></left-menu>
            <left-menu :leftChartData="leftChartData"></left-menu>
        </div>
        <div class="rightMenu">
            <right-menu></right-menu>
            <right-menu :rightChartData="rightChartData"></right-menu>
        </div>
        <div class="bottomMenu">
            <bottomMenu @childData="childData"></bottomMenu>
@@ -42,6 +42,7 @@
import analysis from '@/views/visual/analysis/index.vue'
import lineLoss from './lineLoss.vue';
import statistics from '@/views/visual/statistics/index.vue'
import { type } from 'jquery';
export default {
    components: {
        mapView, leftMenu,
@@ -50,12 +51,50 @@
    data() {
        return {
            isShow: null,
            showInfo: false
            showInfo: false,
            wsSocket: null,
            rightChartData: {},
            leftChartData:{},
        }
    },
    beforeDestroy() {
        if (this.wsSocket) {
            this.wsSocket.onclose = () => {
                console.log('WebSocket连接关闭');
                this.wsSocket = null
            };
        }
    },
    mounted() {
        if (!this.wsSocket) {
            this.createSocket();
        }
    },
    methods: {
        createSocket() {
            this.wsSocket = new WebSocket(config.pySocket);
            this.wsSocket.onopen = (event) => {
                console.log('WebSocket连接成功');
            };
            this.wsSocket.onmessage = (event) => {
                // console.log('Received message:', event.data);
                if (event.data != "连接成功") {
                    const obj = JSON.parse(event.data)
                    this.leftChartData = {
                        type: 'left1',
                        val: obj
                    }
                }
                // 处理接收到的消息
            };
        },
        childData(res) {
            if (!res) return
            this.showInfo = true;
src/views/visualization/leftMenu.vue
@@ -2,6 +2,9 @@
    <div class="leftMnu">
        <div class="menuBox">
            <div class="aside-title">{{ title.t1 }}</div>
            <div class="echartBox">
                <div id="letftEchart1" class="chartBox"></div>
            </div>
        </div>
        <div class="menuBox">
            <div class="aside-title">{{ title.t2 }}</div>
@@ -13,13 +16,103 @@
</template>
<script>
import * as echarts from 'echarts';
export default {
    props: {
        leftChartData: {
            type: Object,
            required: true
        },
    },
    data() {
        return {
            title: {
                t1: 'xxx',
                t2: 'XXXX',
                t3: 'xxxxx'
            },
            myLeftChart1: null,
            leftChartOption: {
                lenData: [],
                xData: [],
                serData: [],
            },
        }
    },
    watch: {
        leftChartData: {
            deep: true,
            handler(res) {
                if (res) {
                    if (res.type == "left1") {
                        this.setLeftChart1(res.val)
                    }
                }
            }
        }
    },
    methods: {
        setLeftChart1(res) {
            console.log(res);
            if (!this.myLeftChart1) {
                this.myLeftChart1 = echarts.init(document.getElementById('letftEchart1'));
            }
            if (this.leftChartOption.lenData.length == 0) {
                this.title.t1 = res.head[1]
                this.leftChartOption.lenData.push(res.head[0])
                const colors=['#67C23A','#E6A23C','#F56C6C']
                for (var i = 0; i < 3; i++) {
                    this.leftChartOption.serData.push({
                        name: res.head[i+1],
                        type: 'line',
                        stack: 'Total',
                        data: [],
                        lineStyle: {
                            color: colors[i], // 折线颜色
                        }
                    })
                }
            }
            var option = this.getChartOption(res)
            this.myLeftChart1 && this.myLeftChart1.setOption(option);
        },
        getChartOption(res) {
            for(var i = 0;i<3;i++){
                this.leftChartOption.serData[i].data.push(res.data[i+1])
            }
            this.leftChartOption.xData.push(res.data[0])
            return {
                legend: {
                    show: false
                },
                tooltip: {
                    trigger: 'axis'
                },
                xAxis: {
                    type: 'category',
                    boundaryGap: false,
                    data: this.leftChartOption.xData,
                    axisLine: {
                        lineStyle: {
                            color: 'white' // 设置为红色
                        }
                    }
                },
                yAxis: {
                    type: 'value',
                    axisLine: {
                        lineStyle: {
                            color: 'white' // 设置为红色
                        }
                    }
                },
                series: this.leftChartOption.serData
            }
        }
    }
@@ -40,6 +133,8 @@
        background: url(~@/assets/images/Screen/chartbg.png);
        background-size: 100% 100%;
        background-repeat: no-repeat;
        display: flex;
        flex-direction: column;
        .aside-title {
            box-sizing: border-box;
@@ -55,6 +150,19 @@
            background-size: 100% 100%;
            background-repeat: no-repeat;
        }
        .echartBox {
            flex: 1;
            padding: 5px;
            position: relative;
            .chartBox {
                width: calc(100% - 10px);
                height: calc(100% - 10px);
                position: absolute;
            }
        }
    }
}
</style>
src/views/visualization/rightMenu.vue
@@ -25,6 +25,12 @@
import * as echarts from 'echarts';
export default {
  props: {
    rightChartData: {
      type: Object,
      required: true
    },
  },
  data() {
    return {
      title: {
@@ -34,6 +40,19 @@
      }
    }
  },
  watch: {
    rightChartData: {
      deep: true,
      handler(val) {
        if (val) {
          if(val.type=='"right1"'){
          }
        }
      }
    }
  },
  mounted() {
    this.initEchart();
  },