|
|
@@ -1,1218 +1,1299 @@
|
|
|
-<template>
|
|
|
- <div class="main">
|
|
|
- <el-row>
|
|
|
- <el-col :span="1">
|
|
|
- <div class="map-edit-conent_button">
|
|
|
- <!-- <transition name="el-zoom-in-top"> -->
|
|
|
- <div class="map-element-browsing" v-show="eleBrowsingShow">
|
|
|
- <div class="element-title" @click="eleBrowsingShow = false"><i class="el-icon-error"></i></div>
|
|
|
- <div class="element-data">
|
|
|
- <el-tabs type="border-card" v-model="elementActiveName">
|
|
|
- <el-tab-pane label="点" name="point">
|
|
|
- <el-table :data="pointData" style="width: 100%" :max-height="'330px'" border>
|
|
|
- <el-table-column prop="id" label="id" width="65">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="name" label="名称" show-overflow-tooltip width="80">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="110">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-location-outline"
|
|
|
- @click="watchEle(scope.row.id)">查看</el-button>
|
|
|
- <el-popconfirm title="删除选中的元素?" @confirm="removeElement(scope.row.id)">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" slot="reference"
|
|
|
- style="margin-left: 5px;">删除</el-button>
|
|
|
- </el-popconfirm>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
- <el-tab-pane label="线" name="line">
|
|
|
- <el-table :data="lineData" style="width: 100%" :max-height="'330px'" border>
|
|
|
- <el-table-column prop="id" label="id" width="65">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="name" label="名称" show-overflow-tooltip width="80">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="110">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-location-outline"
|
|
|
- @click="watchEle(scope.row.id)">查看</el-button>
|
|
|
- <el-popconfirm title="删除选中的元素?" @confirm="removeElement(scope.row.id)">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" slot="reference"
|
|
|
- style="margin-left: 5px;">删除</el-button>
|
|
|
- </el-popconfirm>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
- <el-tab-pane label="弧" name="arc">
|
|
|
- <el-table :data="bowData" style="width: 100%" :max-height="'330px'" border>
|
|
|
- <el-table-column prop="id" label="id" width="65">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="name" label="名称" show-overflow-tooltip width="80">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="110">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-location-outline"
|
|
|
- @click="watchEle(scope.row.id)">查看</el-button>
|
|
|
- <el-popconfirm title="删除选中的元素?" @confirm="removeElement(scope.row.id)">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" slot="reference"
|
|
|
- style="margin-left: 5px;">删除</el-button>
|
|
|
- </el-popconfirm>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
- <el-tab-pane label="面" name="surface">
|
|
|
- <el-table :data="shapeData" style="width: 100%" :max-height="'330px'" border>
|
|
|
- <el-table-column prop="id" label="id" width="65">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column prop="name" label="名称" show-overflow-tooltip width="80">
|
|
|
- </el-table-column>
|
|
|
- <el-table-column label="操作" align="center" width="110">
|
|
|
- <template slot-scope="scope">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-location-outline"
|
|
|
- @click="watchEle(scope.row.id)">查看</el-button>
|
|
|
- <el-popconfirm title="删除选中的元素?" @confirm="removeElement(scope.row.id)">
|
|
|
- <el-button size="mini" type="text" icon="el-icon-delete" slot="reference"
|
|
|
- style="margin-left: 5px;">删除</el-button>
|
|
|
- </el-popconfirm>
|
|
|
- </template>
|
|
|
- </el-table-column>
|
|
|
- </el-table>
|
|
|
- </el-tab-pane>
|
|
|
- </el-tabs>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <!-- </transition> -->
|
|
|
- <div class="button-item">
|
|
|
- <el-tooltip class="item" effect="dark" content="元素选择" placement="right" :hide-after="1000">
|
|
|
- <el-button class="button-item_button"><img src="@/assets/icons/img/hand.png"
|
|
|
- :class="['notification__image', { 'element_select_button': isChoose == 'select' }]"
|
|
|
- style="opacity: 0.6;" width="25px" height="25px" @click="elementSelect" /></el-button>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div class="button-item">
|
|
|
- <el-tooltip class="item" effect="dark" content="地图编辑" placement="right" :hide-after="400">
|
|
|
- <el-popover placement="right" title="选择元素" width="170" trigger="hover" ref="editPopover">
|
|
|
- <div class="close-edit">
|
|
|
- <el-button type="danger" size="mini" style="padding: 3px 7px;border-radius: 0;"
|
|
|
- v-show="!pointDraSelectEnabled" @click="closeEditModle">退出编辑</el-button>
|
|
|
- </div>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="12">
|
|
|
- <div class="button-item_grid-content" ref="drPoint" @click="drawModle('drPoint')"><el-button
|
|
|
- class="button-item_button-dra"><img src="@/assets/icons/img/point.png"
|
|
|
- class="notification__image" style="opacity: 0.6;" width="30px" height="30px" /></el-button>
|
|
|
- <div><span>绘点</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <div class="button-item_grid-content" ref="drLine" @click="drawModle('drLine')"><el-button
|
|
|
- class="button-item_button-dra"><img src="@/assets/icons/img/line.png"
|
|
|
- class="notification__image" style="opacity: 0.6;" width="30px" height="30px" /></el-button>
|
|
|
- <div><span>绘线</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <div style="width: 100%;height: 20px;"></div>
|
|
|
- <el-row :gutter="10">
|
|
|
- <el-col :span="12">
|
|
|
- <div class="button-item_grid-content" ref="drCurve" @click="drawModle('drCurve')"><el-button
|
|
|
- class="button-item_button-dra"><img src="@/assets/icons/img/curve.png"
|
|
|
- class="notification__image" width="30px" height="30px" /></el-button>
|
|
|
- <div><span>曲线</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <div class="button-item_grid-content" ref="drGraphics" @click="drawModle('drGraphics')"><el-button
|
|
|
- class="button-item_button-dra"><img src="@/assets/icons/img/region.png"
|
|
|
- class="notification__image" width="30px" height="30px" /></el-button>
|
|
|
- <div><span>区域</span></div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <el-button class="button-item_button" slot="reference" @click="eleBrowsingShow = false"><img
|
|
|
- src="@/assets/icons/img/draw.png"
|
|
|
- :class="['notification__image', { 'element_select_button': isChoose == 'edit' }]"
|
|
|
- style="opacity: 0.6;" width="25px" height="25px" /></el-button>
|
|
|
- </el-popover>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div class="button-item" @click="eleBrowsingShow = !eleBrowsingShow">
|
|
|
- <el-tooltip class="item" effect="dark" content="元素预览" placement="right" :hide-after="500">
|
|
|
- <el-button class="button-item_button"><img src="@/assets/icons/img/element.png"
|
|
|
- class="notification__image" style="opacity: 0.6;" width="25px" height="25px" /></el-button>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div class="button-item">
|
|
|
- <el-tooltip class="item" effect="dark" content="路网操作" placement="right" :hide-after="500">
|
|
|
- <el-popover placement="bottom-start" width="160" trigger="manual" v-model="visible"
|
|
|
- transition="el-zoom-in-top">
|
|
|
- <div class="roadnetword-content">
|
|
|
- <el-button class="roadnetword-content_button">导出路网</el-button>
|
|
|
- <el-button class="roadnetword-content_button">导入路网</el-button>
|
|
|
- <el-button class="roadnetword-content_button">合并导入路网</el-button>
|
|
|
- <el-button class="roadnetword-content_button">增量导入路网</el-button>
|
|
|
- <el-button class="roadnetword-content_button">覆盖导入路网</el-button>
|
|
|
- </div>
|
|
|
- <el-button class="button-item_button" slot="reference" @click="visible = !visible"><img
|
|
|
- class="notification__image" src="@/assets/icons/img/roadnetwork.png" style="opacity: 0.6;"
|
|
|
- width="25px" height="25px" /></el-button>
|
|
|
- </el-popover>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div class="save-button">
|
|
|
- <el-button type="primary" size="mini" style="padding: 5px 10px;" @click="saveRoute">保存</el-button>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- <el-col :span="23">
|
|
|
- <div class="map-edit-conent">
|
|
|
- <!-- 地图内容 -->
|
|
|
- <OlMap ref="olmap" :width="olWidth + 'px'" :height="olHeight + 'px'" backgroundColor="#F5F5F5"
|
|
|
- :pointDraSelectEnabled="pointDraSelectEnabled" @elementRoadInitEnd="elementRoadInitEnd"
|
|
|
- @elementRoadDrawEnd="elementRoadDrawEnd" @removeElementResult="removeElementResult"
|
|
|
- @selectShowEleResult="selectShowEleResult":mapName="mapName"></OlMap>
|
|
|
- </div>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- <div class="info-dra-class-all">
|
|
|
- <el-drawer :visible.sync="infoDrawer" :direction="'rtl'" :modal="false" :size="'100%'" :wrapperClosable="false"
|
|
|
- custom-class="navigation-info-dra-class" :modal-append-to-body="false" :withHeader="false">
|
|
|
- <div class="info-dra-class_content">
|
|
|
- <div style="margin-bottom: 20px;position: relative;">
|
|
|
- <div class="info-dra_title">
|
|
|
- <div
|
|
|
- style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
|
|
|
- </div><span>当前地图</span>
|
|
|
- <i class="el-icon-close" style="position: absolute;cursor: pointer;right: 0;top: 0;"
|
|
|
- @click="infoDrawer = false"></i>
|
|
|
- </div>
|
|
|
- <span class="info-dra_content">shanghai</span>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="info-dra_title">
|
|
|
- <div
|
|
|
- style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
|
|
|
- </div><span>实时信息</span>
|
|
|
- </div>
|
|
|
- <span class="info-dra_content info-dra_content_title">速度: <span
|
|
|
- class="info-dra_content_other">0.35m/s</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">速度指令: <span
|
|
|
- class="info-dra_content_other">0.22m/s</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">坐标: <span class="info-dra_content_other">(1.813,
|
|
|
- -63.931,
|
|
|
- 0.000)</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">航向: <span
|
|
|
- class="info-dra_content_other">-79.6°</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">累计里程: <span
|
|
|
- class="info-dra_content_other">5965352.00m</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">配准误差: <span
|
|
|
- class="info-dra_content_other">10.000</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">电量: <span
|
|
|
- class="info-dra_content_other">67%</span></span>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 20px;">
|
|
|
- <div class="info-dra_title" style="border-bottom: none;">
|
|
|
- <div
|
|
|
- style="height: 20px;width: 5px;background-color: #6565FC;margin-right: 5px;border-radius: 4px 4px 0 0;">
|
|
|
- </div><span>实时位姿</span>
|
|
|
- <div style="position: absolute;right: 0;"></div>
|
|
|
- </div>
|
|
|
- <span class="info-dra_content info-dra_content_title">x坐标: <span
|
|
|
- class="info-dra_content_other">0.35m/s</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">y坐标: <span
|
|
|
- class="info-dra_content_other">0.22m/s</span></span>
|
|
|
- <span class="info-dra_content info-dra_content_title">z坐标: <span
|
|
|
- class="info-dra_content_other">0.22m/s</span></span>
|
|
|
- <el-button plain size="mini" icon="el-icon-circle-plus-outline" @click="addCurrentMapShow = true"
|
|
|
- style="color: #6565FC;">添加当前点</el-button>
|
|
|
- </div>
|
|
|
-
|
|
|
- <div class="element-pram-box" v-if="currentFeature.id">
|
|
|
- <div class="info-dra_title" style="border-bottom: none;margin-bottom: 0;">
|
|
|
- <span>当前元素参数</span>
|
|
|
- <div style="position: absolute;right: 0;"><el-button type="text"><i
|
|
|
- :class="elementPramShow ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
|
|
|
- @click="elementPramShow = !elementPramShow"></i></el-button></div>
|
|
|
- </div>
|
|
|
- <div v-show="elementPramShow" style="margin-top: 10px;">
|
|
|
- <!-- 点位类型 -->
|
|
|
- <template v-if="currentFeature.typeEle == 'Point'">
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">id:</span>
|
|
|
- <el-input v-model="currentFeature.id" size="mini" style="margin-bottom: 5px;width: 40%;"
|
|
|
- :disabled="true"></el-input>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">名称:</span>
|
|
|
- <el-tooltip class="item" effect="dark" content="输入完毕点击一次右侧√即可" placement="top">
|
|
|
- <el-input v-model="currentFeature.name" size="mini" style="margin-bottom: 5px;width: 50%;"
|
|
|
- @change="setProperties">
|
|
|
- <template slot="append"><el-button type="success" size="mini"><i
|
|
|
- class="el-icon-check"></i></el-button></template>
|
|
|
- </el-input>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">x坐标(m):</span>
|
|
|
- <el-input-number v-model="currentFeature.position[0]" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="positionEdit()" :step="0.5"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">y坐标(m):</span>
|
|
|
- <el-input-number v-model="currentFeature.position[1]" controls-position="right" size="mini"
|
|
|
- @change="positionEdit()" :step="0.5" style="margin-bottom: 5px;width: 50%;"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">z坐标(m):</span>
|
|
|
- <el-input-number v-model="currentFeature.position[2]" controls-position="right" size="mini"
|
|
|
- @change="positionEdit()" :step="0.5" style="margin-bottom: 5px;width: 50%;"></el-input-number>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <!-- 线类型 -->
|
|
|
- <template v-if="currentFeature.typeEle == 'LineString'">
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">id:</span>
|
|
|
- <el-input v-model="currentFeature.id" size="mini" style="margin-bottom: 5px;width: 40%;"
|
|
|
- :disabled="true"></el-input>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">名称:</span>
|
|
|
- <el-tooltip class="item" effect="dark" content="输入完毕点击一次右侧√即可" placement="top">
|
|
|
- <el-input v-model="currentFeature.name" size="mini" style="margin-bottom: 5px;width: 50%;"
|
|
|
- @change="setProperties">
|
|
|
- <template slot="append"><el-button type="success" size="mini"><i
|
|
|
- class="el-icon-check"></i></el-button></template>
|
|
|
- </el-input>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">起点id:</span>
|
|
|
- <el-input v-model="currentFeature.startid" size="mini" style="margin-bottom: 5px;width: 40%;"
|
|
|
- :disabled="true"></el-input>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">终点id:</span>
|
|
|
- <el-input v-model="currentFeature.endid" size="mini" style="margin-bottom: 5px;width: 40%;"
|
|
|
- :disabled="true"></el-input>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <el-tooltip class="item" effect="dark"
|
|
|
- content="车辆在线路上的运动模式,解释: 1.前进-允许车辆正开从起点运动到终点 2.倒行-允许车辆倒开从起点运动到终点" placement="top">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">起点->终点<i class="el-icon-question"></i></span>
|
|
|
- </el-tooltip>
|
|
|
- <div style="margin-top: 10px;">
|
|
|
- <el-checkbox v-model="currentFeature.directList[0]" @change="setProperties">前行</el-checkbox>
|
|
|
- <el-checkbox v-model="currentFeature.directList[1]" @change="setProperties">倒行</el-checkbox>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <el-tooltip class="item" effect="dark"
|
|
|
- content="车辆在线路上的运动模式,解释: 1.前进-允许车辆正开从终点运动到起点 2.倒行-允许车辆倒开从终点运动到起点" placement="top">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">终点->起点<i class="el-icon-question"></i></span>
|
|
|
- </el-tooltip>
|
|
|
- <div style="margin-top: 10px;">
|
|
|
- <el-checkbox v-model="currentFeature.directList[2]" @change="setProperties">前行</el-checkbox>
|
|
|
- <el-checkbox v-model="currentFeature.directList[3]" @change="setProperties">倒行</el-checkbox>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">最大限速(m/s):</span>
|
|
|
- <el-input-number v-model="currentFeature.maxspeed" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">最小限速(m/s):</span>
|
|
|
- <el-input-number v-model="currentFeature.minspeed" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">车道宽度(m):</span>
|
|
|
- <el-input-number v-model="currentFeature.lanewidth" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">左车道数:</span>
|
|
|
- <el-input-number v-model="currentFeature.leftlanenum" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">右车道处:</span>
|
|
|
- <el-input-number v-model="currentFeature.rightlanenum" controls-position="right" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <!-- 面类型 -->
|
|
|
- <template v-if="currentFeature.typeEle == 'Polygon'">
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">id:</span>
|
|
|
- <el-input v-model="currentFeature.id" size="mini" style="margin-bottom: 5px;width: 40%;"
|
|
|
- :disabled="true"></el-input>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">名称:</span>
|
|
|
- <el-tooltip class="item" effect="dark" content="输入完毕点击一次右侧√即可" placement="top">
|
|
|
- <el-input v-model="currentFeature.name" size="mini" style="margin-bottom: 5px;width: 50%;"
|
|
|
- @change="setProperties">
|
|
|
- <template slot="append"><el-button type="success" size="mini"><i
|
|
|
- class="el-icon-check"></i></el-button></template>
|
|
|
- </el-input>
|
|
|
- </el-tooltip>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">类型:</span>
|
|
|
- <el-select v-model="currentFeature.type" placeholder="请选择" size="mini"
|
|
|
- style="margin-bottom: 5px;width: 50%;" @change="setProperties">
|
|
|
- <el-option v-for="item in snapeTypeRange" :key="item.value" :label="item.label" :value="item.value">
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">颜色:</span>
|
|
|
- <el-color-picker v-model="currentFeature.color" size="mini" @change="setProperties"></el-color-picker>
|
|
|
- </div>
|
|
|
- <div style="margin-bottom: 5px;" class="ele-pram-input">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">透明度:</span>
|
|
|
- <el-slider v-model="currentFeature.transparent" style="margin-bottom: 5px;width: 50%;" :max="255"
|
|
|
- :step="5" @change="setProperties"></el-slider>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="element-pram-box" style="margin-bottom: 0;" v-if="currentFeature.id">
|
|
|
- <div class="info-dra_title" style="border-bottom: none;margin-bottom: 0;">
|
|
|
- <span>当前元素参数高级设置</span>
|
|
|
- <div style="position: absolute;right: 0;"><el-button type="text"><i
|
|
|
- :class="elementPramMoreShow ? 'el-icon-arrow-up' : 'el-icon-arrow-down'"
|
|
|
- @click="elementPramMoreShow = !elementPramMoreShow"></i></el-button></div>
|
|
|
- </div>
|
|
|
- <div v-show="elementPramMoreShow" style="margin-top: 15px;">
|
|
|
- <template v-if="currentFeature.typeEle == 'Point'">
|
|
|
- <div class="ele-data-more">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">航偏角对准使能</span>
|
|
|
- <div class="ele-data-more-title-right">
|
|
|
- <el-switch v-model="currentFeature.isyawfix" active-color="#13ce66" inactive-color="#9D9D9D"
|
|
|
- @change="setProperties">
|
|
|
- </el-switch>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="ele-data-more">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">航偏角(rad)</span>
|
|
|
- <div class="ele-data-more-title-right">
|
|
|
- <el-input-number v-model="currentFeature.yaw" controls-position="right" size="mini"
|
|
|
- @change="setProperties" style="width: 100%;"></el-input-number>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- <template v-if="currentFeature.typeEle == 'LineString'">
|
|
|
- <!-- 线 -->
|
|
|
- <div class="ele-data-more">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">避障方式</span>
|
|
|
- <div class="ele-data-more-title-right">
|
|
|
- <el-select v-model="currentFeature.obstype" placeholder="请选择" size="mini" @change="setProperties">
|
|
|
- <el-option v-for="item in obstypeRange" :key="item.value" :label="item.label" :value="item.value">
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="ele-data-more">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">正向前移(m)</span>
|
|
|
- <div class="ele-data-more-title-right">
|
|
|
- <el-input-number v-model="currentFeature.s2eforward" controls-position="right" size="mini"
|
|
|
- style="width: 100%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="ele-data-more">
|
|
|
- <span style="margin-right: 16px;font-size: 13px;color: #585858;"
|
|
|
- class="info-dra_content_title">逆向前移(m)</span>
|
|
|
- <div class="ele-data-more-title-right">
|
|
|
- <el-input-number v-model="currentFeature.e2sforward" controls-position="right" size="mini"
|
|
|
- style="width: 100%;" @change="setProperties"></el-input-number>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </el-drawer>
|
|
|
- </div>
|
|
|
- <!-- 展开抽屉 -->
|
|
|
- <div class="fixed-right-center" @click="showInfoDra" v-if="!infoDrawer">
|
|
|
- <i class="el-icon-arrow-left"></i>
|
|
|
- </div>
|
|
|
- <!-- 添加当前点位到地图 -->
|
|
|
- <el-dialog title="绘制当前实时位姿到点" :visible.sync="addCurrentMapShow" width="650px" @open="openCurrentToMapDia">
|
|
|
- <el-form ref="form" :model="currentRobotRecord" label-width="110px">
|
|
|
- <el-row>
|
|
|
- <el-col :span="12"><el-form-item label="x坐标(m)">
|
|
|
- <el-input-number v-model="currentRobotRecord.x" controls-position="right"></el-input-number>
|
|
|
- </el-form-item></el-col>
|
|
|
- <el-col :span="12"><el-form-item label="y坐标(m)">
|
|
|
- <el-input-number v-model="currentRobotRecord.y" controls-position="right"></el-input-number>
|
|
|
- </el-form-item></el-col>
|
|
|
- </el-row>
|
|
|
- <el-row>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="航偏角">
|
|
|
- <el-input-number v-model="currentRobotRecord.angle" controls-position="right"
|
|
|
- :disabled="true"></el-input-number>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- <el-col :span="12">
|
|
|
- <el-form-item label="航偏角使能">
|
|
|
- <el-switch v-model="currentRobotRecord.angleEnable"></el-switch>
|
|
|
- </el-form-item>
|
|
|
- </el-col>
|
|
|
- </el-row>
|
|
|
- </el-form>
|
|
|
- <span slot="footer" class="dialog-footer">
|
|
|
- <el-button @click="addCurrentMapShow = false">取 消</el-button>
|
|
|
- <el-button type="primary" @click="addCurrentToMap">确 定</el-button>
|
|
|
- </span>
|
|
|
- </el-dialog>
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
-import OlMap from "@/components/OlMap";
|
|
|
-
|
|
|
-export default {
|
|
|
- name: "EditPage",
|
|
|
- components: {
|
|
|
- OlMap
|
|
|
- },
|
|
|
- data() {
|
|
|
- return {
|
|
|
- // 弹出层标题
|
|
|
- title: "",
|
|
|
- eleBrowsingShow: false,
|
|
|
- visible: false,
|
|
|
- poseValue: false,
|
|
|
- elementPramShow: true,
|
|
|
- elementPramMoreShow: false,
|
|
|
- pointData: [],
|
|
|
- lineData: [],
|
|
|
- bowData: [],
|
|
|
- shapeData: [],
|
|
|
- elementActiveName: 'point',
|
|
|
- infoDrawer: true,
|
|
|
- olWidth: 0, // 用于存储宽度的变量
|
|
|
- olHeight: 0,
|
|
|
- // 当前启用的按钮名
|
|
|
- isChoose: '',
|
|
|
- // 元素选择模式是否启用
|
|
|
- pointDraSelectEnabled: true,
|
|
|
- // 当前所有元素原始对象Feature,包含新绘的
|
|
|
- resourcesFeature: [],
|
|
|
- // 无人车坐标数据
|
|
|
- robotPoseData: {
|
|
|
- x: 0,
|
|
|
- y: 0,
|
|
|
- angle: 0
|
|
|
- },
|
|
|
- // 当前选择的feature
|
|
|
- currentFeature: {},
|
|
|
- // 实时位置绘制点位的dialog
|
|
|
- addCurrentMapShow: false,
|
|
|
- currentRobotRecord: {},
|
|
|
- // 避障方式
|
|
|
- obstypeRange: [
|
|
|
- { label: '停车等待', value: 0 },
|
|
|
- { label: '车道绕障', value: 1 },
|
|
|
- { label: '路网绕障', value: 2 }
|
|
|
- ],
|
|
|
- // 区域类型
|
|
|
- snapeTypeRange: [
|
|
|
- { label: '隔离区域', value: 0 },
|
|
|
- { label: '装饰区域', value: 1 },
|
|
|
- { label: '禁行区域', value: 2 },
|
|
|
- { label: '会车管制区', value: 3 },
|
|
|
- { label: '道闸管控区', value: 4 },
|
|
|
- { label: 'GPS定位区', value: 11 },
|
|
|
- { label: '动态禁行区', value: 22 },
|
|
|
- ],
|
|
|
- haveDraw: false, // 是否操作过页面元素(新增修改或者删除元素) (在切换页面或者刷新时进行拦截,避免误操作退出页面)
|
|
|
- mapName:this.$route.params.mapName
|
|
|
- };
|
|
|
- },
|
|
|
- created() {
|
|
|
-
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- window.removeEventListener("beforeunload", this.handleBeforeUnload);
|
|
|
- },
|
|
|
- beforeRouteLeave(to, from, next) {
|
|
|
- // 如果页面有修改或者新增删除,则拦截*前端路由跳转*, 二次确认
|
|
|
- this.$confirm('当前页面的地图修改还未保存,确定要跳转或退出?', '提示', {
|
|
|
- confirmButtonText: '确定',
|
|
|
- cancelButtonText: '取消',
|
|
|
- type: 'warning'
|
|
|
- }).then(() => {
|
|
|
- next();
|
|
|
- }).catch(() => {
|
|
|
- next(false);
|
|
|
- });
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- const mapId = this.$route.params.mapId;
|
|
|
- this.updateOlCss();
|
|
|
- this.elementSelect();
|
|
|
- window.addEventListener('resize', this.updateOlCss);
|
|
|
- window.addEventListener("beforeunload", this.handleBeforeUnload);
|
|
|
- },
|
|
|
- methods: {
|
|
|
- updateOlCss() {
|
|
|
- const element = this.$el.querySelector('.map-edit-conent');
|
|
|
- this.olWidth = element.offsetWidth;
|
|
|
- this.olHeight = element.offsetHeight;
|
|
|
- },
|
|
|
- handleBeforeUnload(event) {
|
|
|
- // 如果页面有修改或者新增删除,则强制拦截*浏览器主体*的刷新,和关闭操作, 二次确认
|
|
|
- if (this.haveDraw) {
|
|
|
- event.preventDefault();
|
|
|
- event.returnValue = "";
|
|
|
- }
|
|
|
- },
|
|
|
- // 展开右侧实时信息
|
|
|
- showInfoDra() {
|
|
|
- this.infoDrawer = true;
|
|
|
- },
|
|
|
- // 启用地图绘制模式 modle(绘制模式)点线面
|
|
|
- drawModle(modle) {
|
|
|
- // 将当前编辑按钮标记为选中状态
|
|
|
- this.isChoose = 'edit';
|
|
|
- this.pointDraSelectEnabled = false;
|
|
|
- this.addSelectedBrage(modle);
|
|
|
- this.$notify({
|
|
|
- title: '地图编辑',
|
|
|
- message: '已开启地图绘制模式',
|
|
|
- type: 'success',
|
|
|
- duration: 1500
|
|
|
- });
|
|
|
- // this.$refs.editPopover.doClose(); // 进入编辑模式是否关闭编辑元素选择画板, 可以选择启停
|
|
|
- switch (modle) {
|
|
|
- case 'drPoint':
|
|
|
- // 绘制点模式
|
|
|
- this.$refs.olmap.drawPoint();
|
|
|
- break;
|
|
|
- case 'drLine':
|
|
|
- // 绘制线模式
|
|
|
- this.$refs.olmap.drawLine();
|
|
|
- break;
|
|
|
- case 'drCurve':
|
|
|
- // 绘制曲线模式
|
|
|
- this.$refs.olmap.drawCurve();
|
|
|
- break;
|
|
|
- case 'drGraphics':
|
|
|
- this.$refs.olmap.drawPolygon();
|
|
|
- // 绘制图形模式
|
|
|
- break;
|
|
|
- }
|
|
|
- },
|
|
|
- // 关闭绘图模式
|
|
|
- closeEditModle() {
|
|
|
- this.$refs.editPopover.doClose();
|
|
|
- this.isChoose = '';
|
|
|
- // 去除所有选择的绘图元素
|
|
|
- this.addSelectedBrage('');
|
|
|
- this.$notify({
|
|
|
- title: '地图编辑',
|
|
|
- message: '已关闭地图绘制模式',
|
|
|
- type: 'info',
|
|
|
- duration: 1000
|
|
|
- });
|
|
|
- this.$refs.olmap.clearDraw();
|
|
|
- },
|
|
|
- // 为绘图元素添加选中效果
|
|
|
- addSelectedBrage(modle) {
|
|
|
- let refs = ['drPoint', 'drLine', 'drCurve', 'drGraphics'];
|
|
|
- // 遍历 refs 数组
|
|
|
- refs.forEach(ref => {
|
|
|
- const element = this.$refs[ref];
|
|
|
- if (element) {
|
|
|
- // 如果当前元素是 modle,就添加 class
|
|
|
- if (ref == modle) {
|
|
|
- element.classList.add('element_select_button');
|
|
|
- } else {
|
|
|
- // 否则移除 class
|
|
|
- element.classList.remove('element_select_button');
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 开启元素选择模式
|
|
|
- elementSelect() {
|
|
|
- if (this.isChoose != 'select') {
|
|
|
- this.closeEditModle();
|
|
|
- this.$notify({
|
|
|
- title: '地图编辑',
|
|
|
- message: '已开启元素选择模式',
|
|
|
- type: 'success',
|
|
|
- duration: 1000
|
|
|
- });
|
|
|
- // 开启模式
|
|
|
- this.pointDraSelectEnabled = true;
|
|
|
- this.isChoose = 'select';
|
|
|
- const mapElement = document.querySelector('.map-edit-conent'); // 地图视图的 DOM 元素
|
|
|
- mapElement.style.cursor = 'pointer'; // 设置鼠标样式为手
|
|
|
- }
|
|
|
- },
|
|
|
- // 地图元素加载完毕的回执
|
|
|
- elementRoadInitEnd(features) {
|
|
|
- features.forEach(item => {
|
|
|
- // 检查 item.values_ 和 item.values_.id 是否存在
|
|
|
- if (item.values_ && item.values_.id) {
|
|
|
- const id = item.values_.id;
|
|
|
- const data = {
|
|
|
- id: id,
|
|
|
- name: item.values_.name,
|
|
|
- type: item.getGeometry().getType()
|
|
|
- };
|
|
|
- // 根据 id 前缀分类存入对应数组
|
|
|
- if (id.startsWith('p')) {
|
|
|
- this.pointData.push(data);
|
|
|
- } else if (id.startsWith('l')) {
|
|
|
- this.lineData.push(data);
|
|
|
- } else if (id.startsWith('b')) {
|
|
|
- this.bowData.push(data);
|
|
|
- } else if (id.startsWith('s')) {
|
|
|
- this.shapeData.push(data);
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- // 对分类后的数组按数字部分排序
|
|
|
- this.pointData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
- this.lineData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
- this.bowData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
- this.shapeData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
- this.resourcesFeature = features;
|
|
|
- },
|
|
|
- // 某个元素绘制完成的回调
|
|
|
- elementRoadDrawEnd(feature) {
|
|
|
- const id = feature.values_.id || feature.getId();
|
|
|
- const data = {
|
|
|
- id: id,
|
|
|
- name: feature.values_.name,
|
|
|
- type: feature.getGeometry().getType()
|
|
|
- };
|
|
|
- if (id.startsWith('p')) {
|
|
|
- this.pointData.push(data);
|
|
|
- // 按照类型为feature初始化基础参数和高级参数(点)
|
|
|
- this.initElelmentParamsPonint(feature);
|
|
|
- } else if (id.startsWith('l')) {
|
|
|
- this.lineData.push(data);
|
|
|
- // 按照类型为feature初始化基础参数和高级参数(线)
|
|
|
- this.initElelmentParamsBowOrLine(feature);
|
|
|
- } else if (id.startsWith('b')) {
|
|
|
- this.bowData.push(data);
|
|
|
- // 按照类型为feature初始化基础参数和高级参数(曲线)
|
|
|
- this.initElelmentParamsBowOrLine(feature);
|
|
|
- } else if (id.startsWith('s')) {
|
|
|
- this.shapeData.push(data);
|
|
|
- // 按照类型为feature初始化基础参数和高级参数(面)
|
|
|
- this.initElelmentParamsSnape(feature);
|
|
|
- }
|
|
|
- // 标记当前存在绘制的操作,拦截使用
|
|
|
- this.haveDraw = true; // 是否操作过页面元素(新增修改或者删除元素) (在切换页面或者刷新时进行拦截,避免误操作退出页面)
|
|
|
- },
|
|
|
- // 查看某个元素
|
|
|
- watchEle(id) {
|
|
|
- // 调用地图组件显示元素
|
|
|
- this.$refs.olmap.selectShowEle(id);
|
|
|
- },
|
|
|
- // 查看某个元素的子组件回调
|
|
|
- selectShowEleResult(feature) {
|
|
|
- const geometry = feature.getGeometry();
|
|
|
- console.log(geometry.getCoordinates());
|
|
|
-
|
|
|
- if (geometry.getType() == 'Point') {
|
|
|
- // 如果是点位则临时保存xyz和类型到参数用于渲染(保存时会移除) 注:保存元素坐标为参数用于对应表单数据,否则需要用方法获取,无法双向绑定
|
|
|
- feature.set('position', geometry.getCoordinates())
|
|
|
- } else if (geometry.getType() == "LineString") {
|
|
|
- // 解析线段类型的direct参数用于渲染和修改(保存时需要渲染回原始数据模式,切记)
|
|
|
- const value = feature.values_.direct - 100 || 0;
|
|
|
- const binary = value.toString(2).padStart(4, '0');
|
|
|
- const result = [
|
|
|
- binary[0] === '1', // bit3
|
|
|
- binary[1] === '1', // bit2
|
|
|
- binary[2] === '1', // bit1
|
|
|
- binary[3] === '1' // bit0
|
|
|
- ];
|
|
|
- // 临时参数渲染使用, 保存时会删除
|
|
|
- feature.set('directList', result);
|
|
|
- }
|
|
|
- // 临时保存类型到参数用于渲染(保存时回移除)
|
|
|
- feature.set('typeEle', geometry.getType())
|
|
|
- this.currentFeature = feature.getProperties();
|
|
|
- },
|
|
|
- // 移除某个元素
|
|
|
- removeElement(id) {
|
|
|
- // 调用地图组件移除元素
|
|
|
- this.$refs.olmap.removeElement(id);
|
|
|
- },
|
|
|
- // 移除元素操作的回调
|
|
|
- removeElementResult(id) {
|
|
|
- if (!id) {
|
|
|
- this.$message.error('移除元素失败!');
|
|
|
- return;
|
|
|
- }
|
|
|
- // 删除当前数据table中这个元素
|
|
|
- if (id.startsWith('p')) {
|
|
|
- const index = this.pointData.findIndex(item => item.id === id);
|
|
|
- if (index !== -1) {
|
|
|
- this.pointData.splice(index, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- if (id.startsWith('l')) {
|
|
|
- const index = this.lineData.findIndex(item => item.id === id);
|
|
|
- if (index !== -1) {
|
|
|
- this.lineData.splice(index, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- if (id.startsWith('b')) {
|
|
|
- const index = this.bowData.findIndex(item => item.id === id);
|
|
|
- if (index !== -1) {
|
|
|
- this.bowData.splice(index, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- if (id.startsWith('s')) {
|
|
|
- const index = this.shapeData.findIndex(item => item.id === id);
|
|
|
- if (index !== -1) {
|
|
|
- this.shapeData.splice(index, 1);
|
|
|
- }
|
|
|
- }
|
|
|
- // 判断当前选择元素是否被删除,如果是则删除
|
|
|
- if (this.currentFeature && this.currentFeature.id == id) {
|
|
|
- this.currentFeature = {};
|
|
|
- }
|
|
|
- // 删除源features中的此元素
|
|
|
- const index = this.resourcesFeature.findIndex(feature => feature.getId() == id);
|
|
|
- // 如果找到了该元素,则删除
|
|
|
- if (index !== -1) {
|
|
|
- this.resourcesFeature.splice(index, 1);
|
|
|
- }
|
|
|
- this.haveDraw = true;
|
|
|
- },
|
|
|
- // 初始化点位元素基础和高级参数
|
|
|
- initElelmentParamsPonint(feature) {
|
|
|
- feature.set('name', '');
|
|
|
- feature.set('yaw', 0); // 弧度
|
|
|
- // 如果是通过实时位姿则需要判断是否有值,有则设置
|
|
|
- feature.set('isyawfix', feature.get('isyawfix') ? true : false); // 偏航使能
|
|
|
- feature.set('taskid', 0);
|
|
|
- feature.set('offset', 0);
|
|
|
- feature.set('pitch', 0)
|
|
|
- feature.set('roll', 0)
|
|
|
- this.resourcesFeature.push(feature);
|
|
|
- },
|
|
|
- // 初始化执行元素基础和高级参数
|
|
|
- initElelmentParamsBowOrLine(feature) {
|
|
|
- feature.set('name', '');
|
|
|
- // direct中的值首先需要减去100,结果的后4位bit位分别代表如下含义:
|
|
|
- // bit3:为1时,表示允许车辆从起点行驶到终点,且机器人以正常前行的方式行驶;
|
|
|
- // bit2:为1时,表示允许车辆从起点行驶到终点,且机器人以倒车的方式行驶;
|
|
|
- // bit1:为1时,表示允许车辆从终点行驶到起点,且机器人以正常前行的方式行驶;
|
|
|
- // bit0:为1时,表示允许车辆从终点行驶到起点,且机器人以倒车的方式行驶。
|
|
|
- // 举例: direct=105(bit2和bit0为1),表示为双向车道,但是不论机器人从起点前往终点,还是从终点前往起点,都会以倒车的方式行驶。
|
|
|
- feature.set('direct', 110); // 常用 110:起点至终点 + 终点至起点(双方向) 正向行驶 108:起点至终点 正向行驶
|
|
|
- feature.set('maxspeed', 8) // 最大限速 m/s
|
|
|
- feature.set('minspeed', 0) // 最小限速 m/s
|
|
|
- feature.set('lanewidth', 1) // 车道宽度
|
|
|
- feature.set('leftlanenum', 0) //前进方向左侧车道数
|
|
|
- feature.set('rightlanenum', 0) //前进方向右侧车道数
|
|
|
- feature.set('obstype', 0) // 避障方式,0:停车等待,1:车道绕障,2:路网绕障,默认为0
|
|
|
- feature.set('obsvalue', 200) // 障碍物参数(例如:权重值或影响范围)
|
|
|
- feature.set('followdis', 0.4) // 跟随距离
|
|
|
- feature.set('runtype', 0) // 运行类型
|
|
|
- feature.set('selftheta', 0.5) // 自身角度
|
|
|
- feature.set('xytolerance', 0.2) // 平面坐标容差
|
|
|
- feature.set('s2eforward', 0) // 机器人沿当前线段从起点到达终点时多行驶(负数则为少行驶)的距离,单位为米,默认为0
|
|
|
- feature.set('e2sforward', 0) // 机器人沿当前线段从终点到达起点时多行驶的距离,单位为米,默认为0
|
|
|
- feature.set('thtolerance', 0) // 角度容差
|
|
|
- feature.set('mintheta', 0) // 最小转向角
|
|
|
- feature.set('maxtheta', 1) // 最大转向角
|
|
|
-
|
|
|
- this.resourcesFeature.push(feature);
|
|
|
- },
|
|
|
- // 初始化面元素基础和高级参数
|
|
|
- initElelmentParamsSnape(feature) {
|
|
|
- feature.set('name', '');
|
|
|
- feature.set('typeEle', feature.getGeometry().getType()); // 保存元素类型为参数用于动态绑定对应的元素修改表单,否则需要用方法获取
|
|
|
- feature.set('color', "#7EFFFA");
|
|
|
- //区域类型,说明: 0:隔离区域,限定机器人只能在该区域活动;1:装饰区域,仅人机交互用,不影响导航;
|
|
|
- // 2:禁行区域,不允许机器人进入该区域;3:会车管制区,特定场景使用;
|
|
|
- // 4:道闸管控区,特定场景使用;11:GPS定位区,进入该区域后,从激光定位切换到GPS定位;
|
|
|
- // 22:动态禁行区,特定场景使用。
|
|
|
- feature.set('type', 1);
|
|
|
- feature.set('transparent', 200);
|
|
|
- this.resourcesFeature.push(feature);
|
|
|
- },
|
|
|
- /**
|
|
|
- * 点位坐标修改
|
|
|
- */
|
|
|
- positionEdit() {
|
|
|
- this.haveDraw = true;
|
|
|
- this.$refs.olmap.pointPositionUpdate(this.currentFeature.id, this.currentFeature.position);
|
|
|
- },
|
|
|
- // 自定义参数修改提交
|
|
|
- setProperties() {
|
|
|
- if (!this.currentFeature) return;
|
|
|
- this.resourcesFeature.forEach(item => {
|
|
|
- if (item.getId() == this.currentFeature.id) {
|
|
|
- // 额外参数处理 线
|
|
|
- if (this.currentFeature.id.startsWith('l') || this.currentFeature.id.startsWith('b')) {
|
|
|
- // direct还原
|
|
|
- let directList = this.currentFeature.directList;
|
|
|
- // 将布尔集合转成4位bit集合, 再转成10进制, 加100还原成原始报文
|
|
|
- const binaryString = directList.map(bit => (bit ? '1' : '0')).join('');
|
|
|
- const value = parseInt(binaryString, 2);
|
|
|
- const direct = value + 100;
|
|
|
- this.currentFeature.direct = direct;
|
|
|
- }
|
|
|
- // 处理完毕后先刷新对象到画布
|
|
|
- item.setProperties(this.currentFeature)
|
|
|
- // 刷新完毕后用自定义参数处理其他需要修改完毕能看到的元素效果(例如修改name或者图形颜色等)
|
|
|
- if (this.currentFeature.id.startsWith('s')) {
|
|
|
- // 额外处理多边形的效果
|
|
|
- // 1. 修改图形的颜色,文本
|
|
|
- this.$refs.olmap.editSnapeColor(this.currentFeature.id);
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
- this.haveDraw = true; // 是否操作过页面元素(新增修改或者删除元素) (在切换页面或者刷新时进行拦截,避免误操作退出页面)
|
|
|
- },
|
|
|
- // 保存路网
|
|
|
- saveRoute() {
|
|
|
- // 保存时清理当前所有对象的额外渲染参数
|
|
|
- this.resourcesFeature.forEach(feature => {
|
|
|
- const values = feature.getProperties(); // 获取feature的values_自定义属性
|
|
|
- // 检查并删除特定的属性(如果存在)
|
|
|
- if (values) {
|
|
|
- if (values.hasOwnProperty('typeEle')) {
|
|
|
- delete values.typeEle; // 删除 typeEle 属性
|
|
|
- }
|
|
|
- if (values.hasOwnProperty('position')) {
|
|
|
- delete values.position; // 删除 position 属性
|
|
|
- }
|
|
|
- if (values.hasOwnProperty('directList')) {
|
|
|
- delete values.directList; // 删除 directList 属性
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- // 以当前车辆实时位姿为点位绘制到地图
|
|
|
- addCurrentToMap() {
|
|
|
- this.addCurrentMapShow = false;
|
|
|
- // 使用组件的根据坐标绘制点方法
|
|
|
- let data = [{ yaw: this.currentRobotRecord.angle }, { isyawfix: this.currentRobotRecord.angleEnable }]
|
|
|
- this.$refs.olmap.createPointAtCoordinate([this.currentRobotRecord.x, this.currentRobotRecord.y, 0], '', data);
|
|
|
- },
|
|
|
- openCurrentToMapDia() {
|
|
|
- this.currentRobotRecord = this.robotPoseData;
|
|
|
- this.currentRobotRecord.isyawfix = false;
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.main{
|
|
|
- position: relative;
|
|
|
- min-width: 1200px;
|
|
|
- overflow-x: auto;
|
|
|
-}
|
|
|
-
|
|
|
-.element-title {
|
|
|
- position: absolute;
|
|
|
- z-index: 1001;
|
|
|
- right: 8px;
|
|
|
- top: 8px;
|
|
|
- color: #717171;
|
|
|
- cursor: pointer
|
|
|
-}
|
|
|
-
|
|
|
-.explore-unit {
|
|
|
- margin-left: 8px;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-table__header-wrapper {
|
|
|
- border-radius: 10px 10px 0 0;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-table .el-table__header-wrapper th,
|
|
|
-.el-table .el-table__fixed-header-wrapper th {
|
|
|
- background-color: #f6f6f6;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-table--medium .el-table__cell {
|
|
|
- padding: 8px 0;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-dialog__body {
|
|
|
- padding: 20px 20px 0 20px;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .download-map .el-dialog__body {
|
|
|
- padding: 10px 20px 0 20px !important;
|
|
|
-}
|
|
|
-
|
|
|
-.map-edit-conent {
|
|
|
- width: 100%;
|
|
|
- min-height: calc(100vh - 84px);
|
|
|
-}
|
|
|
-
|
|
|
-.map-edit-conent_button {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- /* 垂直排列子元素 */
|
|
|
- /* 在容器内均匀分布元素 */
|
|
|
- align-items: center;
|
|
|
- /* 水平居中 */
|
|
|
- position: relative;
|
|
|
- width: 100%;
|
|
|
- min-height: calc(100vh - 84px);
|
|
|
-}
|
|
|
-
|
|
|
-.button-item {
|
|
|
- margin: 8% 2%;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .button-item_button {
|
|
|
- padding: 10px 12px;
|
|
|
- border: none;
|
|
|
- background-color: transparent;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .button-item_button-dra {
|
|
|
- padding: 5px 12px;
|
|
|
- border: none;
|
|
|
- background-color: transparent;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-.save-button {
|
|
|
- position: absolute;
|
|
|
- bottom: 10px;
|
|
|
-}
|
|
|
-
|
|
|
-.button-item_grid-content {
|
|
|
- text-align: center;
|
|
|
-}
|
|
|
-
|
|
|
-.map-element-browsing {
|
|
|
- height: 450px;
|
|
|
- width: 290px;
|
|
|
- position: absolute;
|
|
|
- left: 100%;
|
|
|
- border-radius: 0 8px 8px 8px;
|
|
|
-}
|
|
|
-
|
|
|
-.element-data {
|
|
|
- z-index: 1000;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .element-data .el-tabs__header {
|
|
|
- margin: 0 0 5px;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .element-data .el-tabs--border-card>.el-tabs__content {
|
|
|
- padding: 5px 15px 15px 15px;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .element-data .el-tabs--border-card {
|
|
|
- box-shadow: none;
|
|
|
-}
|
|
|
-
|
|
|
-.roadnetword-content {
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- justify-content: center;
|
|
|
-}
|
|
|
-
|
|
|
-.roadnetword-content .roadnetword-content_button {
|
|
|
- margin-left: 0;
|
|
|
- width: 100%;
|
|
|
- margin-bottom: 8px;
|
|
|
- border: none;
|
|
|
- background-color: #F7F7F7;
|
|
|
- border: 1px solid #f0f0f0;
|
|
|
-}
|
|
|
-
|
|
|
-.info-dra-class_content {
|
|
|
- padding: 20px 20px 20px 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.info-dra_title {
|
|
|
- display: flex;
|
|
|
- /* 启用 Flexbox 布局 */
|
|
|
- justify-content: flex-start;
|
|
|
- /* 水平从左排列 */
|
|
|
- align-items: center;
|
|
|
- color: #5e5e5e;
|
|
|
- font-size: 16px;
|
|
|
- font-weight: bold;
|
|
|
- border-bottom: 2px solid #B9B9FF;
|
|
|
- margin-bottom: 10px;
|
|
|
- width: 100%;
|
|
|
- position: relative;
|
|
|
-}
|
|
|
-
|
|
|
-.info-dra_content {
|
|
|
- color: #5A5A5A;
|
|
|
- font-size: 14px;
|
|
|
- margin-left: 8px;
|
|
|
- display: block;
|
|
|
- margin-bottom: 12px;
|
|
|
-}
|
|
|
-
|
|
|
-.info-dra_content_title {
|
|
|
- font-weight: bold;
|
|
|
-}
|
|
|
-
|
|
|
-.info-dra_content_other {
|
|
|
- font-weight: 400;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .info-dra-class-all .el-drawer__wrapper {
|
|
|
- width: 15%;
|
|
|
- left: 85%;
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 1599px) {
|
|
|
- ::v-deep .info-dra-class-all .el-drawer__wrapper {
|
|
|
- width: 18%;
|
|
|
- left: 82%;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 1269px) {
|
|
|
- ::v-deep .info-dra-class-all .el-drawer__wrapper {
|
|
|
- width: 21%;
|
|
|
- left: 79%;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-@media (max-width: 1000px) {
|
|
|
- ::v-deep .info-dra-class-all .el-drawer__wrapper {
|
|
|
- width: 24%;
|
|
|
- left: 76%;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-.fixed-right-center {
|
|
|
- position: fixed;
|
|
|
- top: 50%;
|
|
|
- right: 0;
|
|
|
- transform: translateY(-50%);
|
|
|
- background-color: rgba(0, 0, 255, 0.6);
|
|
|
- padding: 4px;
|
|
|
- color: white;
|
|
|
- border-radius: 6px 0 0 6px;
|
|
|
- cursor: pointer;
|
|
|
-}
|
|
|
-
|
|
|
-.element-pram-box {
|
|
|
- margin-bottom: 20px;
|
|
|
- background-color: #f9f9f9;
|
|
|
- padding: 10px;
|
|
|
- border-radius: 8px;
|
|
|
- border: 1px solid #e9e9e9;
|
|
|
-}
|
|
|
-
|
|
|
-.ele-data-more {
|
|
|
- margin-top: 15px;
|
|
|
- margin-bottom: 15px;
|
|
|
- position: relative;
|
|
|
- display: flex;
|
|
|
- justify-content: space-between;
|
|
|
- /* 左右分布,一个靠左,一个靠右 */
|
|
|
- align-items: center;
|
|
|
- /* 垂直居中 */
|
|
|
- height: 100%;
|
|
|
- /* 确保父容器有高度 */
|
|
|
-}
|
|
|
-
|
|
|
-.ele-data-more-title-right {
|
|
|
- width: 40%;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .ele-pram-input .el-input__inner {
|
|
|
- border: none;
|
|
|
- background-color: #e9e9e9;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .el-table .el-table__header-wrapper th,
|
|
|
-.el-table .el-table__fixed-header-wrapper th {
|
|
|
- background-color: #f6f6f6;
|
|
|
-}
|
|
|
-
|
|
|
-.ele-pram-input {
|
|
|
- display: flex;
|
|
|
- /* 设置为Flexbox布局 */
|
|
|
- align-items: center;
|
|
|
- /* 垂直居中对齐 */
|
|
|
- justify-content: space-between;
|
|
|
-}
|
|
|
-
|
|
|
-.button-item_grid-content:hover {
|
|
|
- text-align: center;
|
|
|
- background-color: #ffc1b9;
|
|
|
- border-radius: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.element_select_button {
|
|
|
- background-color: #ffc1b9;
|
|
|
- border-radius: 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.close-edit {
|
|
|
- position: absolute;
|
|
|
- top: 0;
|
|
|
- right: 0;
|
|
|
-}
|
|
|
-
|
|
|
-::v-deep .element-pram-box .el-input.is-disabled .el-input__inner {
|
|
|
- background-color: #f1f1f1;
|
|
|
- color: #5A5A5A;
|
|
|
-}
|
|
|
-</style>
|
|
|
-
|
|
|
-<style>
|
|
|
-.navigation-info-dra-class {
|
|
|
- background-color: #ffffff;
|
|
|
- box-shadow: none;
|
|
|
- border-radius: 5px 0 0 5px;
|
|
|
-}
|
|
|
-
|
|
|
-.navigation-info-dra-class .el-drawer__header {
|
|
|
- margin-bottom: 20px;
|
|
|
-}
|
|
|
+<template>
|
|
|
+ <div class="edit-page">
|
|
|
+ <!-- 地图容器 -->
|
|
|
+ <div class="map-container">
|
|
|
+ <!-- 左侧工具栏 -->
|
|
|
+ <div class="toolbar-container">
|
|
|
+ <MapToolbar
|
|
|
+ preset="edit"
|
|
|
+ :selected-key="currentMode"
|
|
|
+ @mode-change="handleModeChange"
|
|
|
+ @zoom-in="handleZoomIn"
|
|
|
+ @zoom-out="handleZoomOut"
|
|
|
+ @center-robot="handleCenterRobot"
|
|
|
+ @toggle-fullscreen="handleToggleFullscreen"
|
|
|
+ @save="handleSaveMap"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 地图组件(作为主内容区域) -->
|
|
|
+ <div id="map-stage" class="page-content" ref="mapContent">
|
|
|
+ <OlMap
|
|
|
+ ref="olmap"
|
|
|
+ :width="olWidth + 'px'"
|
|
|
+ :height="olHeight + 'px'"
|
|
|
+ backgroundColor="#F5F5F5"
|
|
|
+ :mapName="mapName"
|
|
|
+ :pointDraSelectEnabled="pointDraSelectEnabled"
|
|
|
+ :showDefaultControls="false"
|
|
|
+ @elementRoadInitEnd="elementRoadInitEnd"
|
|
|
+ @elementRoadDrawEnd="elementRoadDrawEnd"
|
|
|
+ @removeElementResult="removeElementResult"
|
|
|
+ @selectShowEleResult="selectShowEleResult"
|
|
|
+ />
|
|
|
+
|
|
|
+ <!-- 底部Inspector面板 -->
|
|
|
+ <BottomInspector
|
|
|
+ ref="bottomInspector"
|
|
|
+ :visible="inspector.visible"
|
|
|
+ :mode="inspector.mode"
|
|
|
+ :data="inspector.data"
|
|
|
+ :loading="inspector.loading"
|
|
|
+ @edit="handleInspectorEdit"
|
|
|
+ @save="handleInspectorSave"
|
|
|
+ @cancel="handleInspectorCancel"
|
|
|
+ @close="handleInspectorClose"
|
|
|
+ @locate="handleInspectorLocate"
|
|
|
+ @height-change="handleInspectorHeightChange"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧面板 -->
|
|
|
+ <div class="panel-container">
|
|
|
+ <RightPanel
|
|
|
+ mode="edit"
|
|
|
+ panelType="edit"
|
|
|
+ v-model="rightPanelVisible"
|
|
|
+ :overlay="true"
|
|
|
+ :tabs="rightPanelTabs"
|
|
|
+ :initial-tab="'info'"
|
|
|
+ :realtime-info="realtimeInfo"
|
|
|
+ :element-list="allElementList"
|
|
|
+ :selected-element="currentFeature"
|
|
|
+ :element-types="elementTypeCounts"
|
|
|
+ @add-current-point="handleAddCurrentPoint"
|
|
|
+ @element-select="handleElementSelect"
|
|
|
+ @element-edit="handleElementEdit"
|
|
|
+ @element-locate="handleElementLocate"
|
|
|
+ @element-remove="handleElementRemove"
|
|
|
+ @network-export="handleNetworkExport"
|
|
|
+ @network-import="handleNetworkImport"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 添加当前点对话框 -->
|
|
|
+ <el-dialog
|
|
|
+ title="添加当前实时位姿点"
|
|
|
+ :visible.sync="addCurrentMapShow"
|
|
|
+ width="480px"
|
|
|
+ @open="openCurrentToMapDialog"
|
|
|
+ class="add-pose-dialog"
|
|
|
+ :close-on-click-modal="false"
|
|
|
+ :modal="true"
|
|
|
+ :modal-append-to-body="true"
|
|
|
+ :append-to-body="true"
|
|
|
+ center
|
|
|
+ custom-class="centered-dialog"
|
|
|
+ >
|
|
|
+ <div class="dialog-content">
|
|
|
+ <el-form ref="currentPointForm" :model="currentRobotRecord" label-width="90px" size="small" class="pose-form">
|
|
|
+ <div class="form-section">
|
|
|
+ <h4 class="section-title">
|
|
|
+ <i class="el-icon-location-outline"></i>
|
|
|
+ 位置信息
|
|
|
+ </h4>
|
|
|
+ <el-form-item label="X坐标(m)" prop="x">
|
|
|
+ <el-input-number
|
|
|
+ v-model="currentRobotRecord.x"
|
|
|
+ :precision="3"
|
|
|
+ :step="0.1"
|
|
|
+ controls-position="right"
|
|
|
+ placeholder="请输入X坐标值"
|
|
|
+ class="coordinate-input"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="Y坐标(m)" prop="y">
|
|
|
+ <el-input-number
|
|
|
+ v-model="currentRobotRecord.y"
|
|
|
+ :precision="3"
|
|
|
+ :step="0.1"
|
|
|
+ controls-position="right"
|
|
|
+ placeholder="请输入Y坐标值"
|
|
|
+ class="coordinate-input"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="Z坐标(m)" prop="z">
|
|
|
+ <el-input-number
|
|
|
+ v-model="currentRobotRecord.z"
|
|
|
+ :precision="3"
|
|
|
+ :step="0.1"
|
|
|
+ controls-position="right"
|
|
|
+ placeholder="请输入Z坐标值"
|
|
|
+ class="coordinate-input"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="form-section">
|
|
|
+ <h4 class="section-title">
|
|
|
+ <i class="el-icon-guide"></i>
|
|
|
+ 方向配置
|
|
|
+ </h4>
|
|
|
+ <el-form-item label="航偏角(rad)" prop="angle">
|
|
|
+ <el-input-number
|
|
|
+ v-model="currentRobotRecord.angle"
|
|
|
+ :precision="3"
|
|
|
+ :step="0.1"
|
|
|
+ controls-position="right"
|
|
|
+ placeholder="请输入航偏角值"
|
|
|
+ style="width: 100%;"
|
|
|
+ />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="航偏角使能" prop="angleEnable">
|
|
|
+ <el-switch v-model="currentRobotRecord.angleEnable" />
|
|
|
+ </el-form-item>
|
|
|
+ </div>
|
|
|
+ </el-form>
|
|
|
+ </div>
|
|
|
+ <span slot="footer" class="dialog-footer">
|
|
|
+ <el-button @click="addCurrentMapShow = false" size="medium">取 消</el-button>
|
|
|
+ <el-button type="primary" @click="addCurrentToMap" size="medium">
|
|
|
+ <i class="el-icon-check"></i> 确 定
|
|
|
+ </el-button>
|
|
|
+ </span>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import OlMap from "@/components/OlMap"
|
|
|
+import MapToolbar from "./components/shared/MapToolbar.vue"
|
|
|
+import RightPanel from "./components/shared/RightPanel.vue"
|
|
|
+import BottomInspector from "@/components/BottomInspector.vue"
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "EditPage",
|
|
|
+ components: {
|
|
|
+ OlMap,
|
|
|
+ MapToolbar,
|
|
|
+ RightPanel,
|
|
|
+ BottomInspector
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ // 地图相关
|
|
|
+ olWidth: 0,
|
|
|
+ olHeight: 0,
|
|
|
+ mapName: 'demo',
|
|
|
+
|
|
|
+ // 编辑模式相关
|
|
|
+ currentMode: 'select', // 当前编辑模式
|
|
|
+ pointDraSelectEnabled: true, // 元素选择模式是否启用
|
|
|
+
|
|
|
+ // 面板显示控制
|
|
|
+ rightPanelVisible: true,
|
|
|
+
|
|
|
+ // Inspector状态管理
|
|
|
+ inspector: {
|
|
|
+ visible: false,
|
|
|
+ mode: 'view', // 'view' | 'edit'
|
|
|
+ data: null,
|
|
|
+ loading: false
|
|
|
+ },
|
|
|
+
|
|
|
+ // 右侧面板配置
|
|
|
+ rightPanelTabs: ['info', 'elements', 'network'],
|
|
|
+
|
|
|
+ // 实时信息数据
|
|
|
+ realtimeInfo: {
|
|
|
+ currentMap: 'shanghai',
|
|
|
+ currentTask: '地图编辑',
|
|
|
+ speed: '0.35m/s',
|
|
|
+ speedCommand: '0.22m/s',
|
|
|
+ coordinates: '(1.813, -63.931, 0.000)',
|
|
|
+ heading: '-79.6°',
|
|
|
+ totalDistance: '5965352.00m',
|
|
|
+ registrationError: '10.000',
|
|
|
+ batteryLevel: '67%'
|
|
|
+ },
|
|
|
+
|
|
|
+ // 元素数据
|
|
|
+ pointData: [],
|
|
|
+ lineData: [],
|
|
|
+ bowData: [],
|
|
|
+ shapeData: [],
|
|
|
+ resourcesFeature: [], // 所有元素的原始Feature对象
|
|
|
+ currentFeature: {}, // 当前选中的元素
|
|
|
+
|
|
|
+ // 添加当前点对话框
|
|
|
+ addCurrentMapShow: false,
|
|
|
+ currentRobotRecord: {
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ z: 0,
|
|
|
+ angle: 0,
|
|
|
+ angleEnable: false
|
|
|
+ },
|
|
|
+
|
|
|
+ // 机器人位姿数据
|
|
|
+ robotPoseData: {
|
|
|
+ x: 0,
|
|
|
+ y: 0,
|
|
|
+ angle: 0
|
|
|
+ },
|
|
|
+
|
|
|
+ // 页面状态
|
|
|
+ haveDraw: false, // 是否有未保存的更改
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ // 所有元素列表(用于右侧面板)
|
|
|
+ allElementList() {
|
|
|
+ return [
|
|
|
+ ...this.pointData,
|
|
|
+ ...this.lineData,
|
|
|
+ ...this.bowData,
|
|
|
+ ...this.shapeData
|
|
|
+ ];
|
|
|
+ },
|
|
|
+
|
|
|
+ // 元素类型统计
|
|
|
+ elementTypeCounts() {
|
|
|
+ return [
|
|
|
+ { key: 'point', label: '点', count: this.pointData.length },
|
|
|
+ { key: 'line', label: '线', count: this.lineData.length },
|
|
|
+ { key: 'curve', label: '弧', count: this.bowData.length },
|
|
|
+ { key: 'polygon', label: '面', count: this.shapeData.length }
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ // 监听右侧面板显隐变化
|
|
|
+ rightPanelVisible(visible) {
|
|
|
+ this.updateRightWidth(visible ? 380 : 0);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ // 获取地图ID
|
|
|
+ this.mapName = this.$route.params.mapId || 'demo';
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ window.removeEventListener("beforeunload", this.handleBeforeUnload);
|
|
|
+ window.removeEventListener('resize', this.updateMapSize);
|
|
|
+ },
|
|
|
+ beforeRouteLeave(to, from, next) {
|
|
|
+ // 检查Inspector是否有未保存更改
|
|
|
+ const inspectorHasChanges = this.inspector.visible && this.inspector.mode === 'edit' && this.$refs.bottomInspector?.hasUnsavedChanges;
|
|
|
+
|
|
|
+ // 如果页面有修改或者新增删除,则拦截*前端路由跳转*, 二次确认
|
|
|
+ if (this.haveDraw || inspectorHasChanges) {
|
|
|
+ const message = inspectorHasChanges ?
|
|
|
+ 'Inspector中有未保存的元素更改,确定要跳转或退出?' :
|
|
|
+ '当前页面的地图修改还未保存,确定要跳转或退出?';
|
|
|
+
|
|
|
+ this.$confirm(message, '提示', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ // 关闭Inspector
|
|
|
+ if (this.inspector.visible) {
|
|
|
+ this.inspector.visible = false;
|
|
|
+ }
|
|
|
+ next();
|
|
|
+ }).catch(() => {
|
|
|
+ next(false);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ next();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ this.updateMapSize();
|
|
|
+ this.initEditMode();
|
|
|
+ this.updateRightWidth(this.rightPanelVisible ? 380 : 0);
|
|
|
+ window.addEventListener('resize', this.updateMapSize);
|
|
|
+ window.addEventListener("beforeunload", this.handleBeforeUnload);
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // === 页面初始化相关 ===
|
|
|
+
|
|
|
+ // 更新地图尺寸
|
|
|
+ updateMapSize() {
|
|
|
+ const mapContent = this.$refs.mapContent;
|
|
|
+ if (mapContent) {
|
|
|
+ this.olWidth = mapContent.offsetWidth;
|
|
|
+ this.olHeight = mapContent.offsetHeight;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 初始化编辑模式
|
|
|
+ initEditMode() {
|
|
|
+ this.currentMode = 'select';
|
|
|
+ this.pointDraSelectEnabled = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 处理页面刷新/关闭前的确认
|
|
|
+ handleBeforeUnload(event) {
|
|
|
+ if (this.haveDraw) {
|
|
|
+ event.preventDefault();
|
|
|
+ event.returnValue = "";
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 更新右侧面板宽度变量
|
|
|
+ updateRightWidth(width) {
|
|
|
+ const host = this.$el || document.documentElement;
|
|
|
+ host.style.setProperty('--right-panel-width', `${width}px`);
|
|
|
+ },
|
|
|
+
|
|
|
+ // === 工具栏事件处理 ===
|
|
|
+
|
|
|
+ // 处理模式切换
|
|
|
+ handleModeChange(mode) {
|
|
|
+ this.currentMode = mode;
|
|
|
+
|
|
|
+ // 根据模式切换地图交互状态
|
|
|
+ switch (mode) {
|
|
|
+ case 'select':
|
|
|
+ this.pointDraSelectEnabled = true;
|
|
|
+ this.$refs.olmap && this.$refs.olmap.clearDraw && this.$refs.olmap.clearDraw();
|
|
|
+ this.$message.success('已切换到选择模式');
|
|
|
+ break;
|
|
|
+ case 'draw-point':
|
|
|
+ this.pointDraSelectEnabled = false;
|
|
|
+ this.$refs.olmap && this.$refs.olmap.drawPoint && this.$refs.olmap.drawPoint();
|
|
|
+ this.$message.success('已切换到绘点模式');
|
|
|
+ break;
|
|
|
+ case 'draw-line':
|
|
|
+ this.pointDraSelectEnabled = false;
|
|
|
+ this.$refs.olmap && this.$refs.olmap.drawLine && this.$refs.olmap.drawLine();
|
|
|
+ this.$message.success('已切换到绘线模式');
|
|
|
+ break;
|
|
|
+ case 'draw-curve':
|
|
|
+ this.pointDraSelectEnabled = false;
|
|
|
+ this.$refs.olmap && this.$refs.olmap.drawCurve && this.$refs.olmap.drawCurve();
|
|
|
+ this.$message.success('已切换到绘曲线模式');
|
|
|
+ break;
|
|
|
+ case 'draw-polygon':
|
|
|
+ this.pointDraSelectEnabled = false;
|
|
|
+ this.$refs.olmap && this.$refs.olmap.drawPolygon && this.$refs.olmap.drawPolygon();
|
|
|
+ this.$message.success('已切换到绘区域模式');
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // 工具栏基础操作
|
|
|
+ handleZoomIn() {
|
|
|
+ // TODO: 实现地图放大
|
|
|
+ this.$message.info('地图放大');
|
|
|
+ },
|
|
|
+
|
|
|
+ handleZoomOut() {
|
|
|
+ // TODO: 实现地图缩小
|
|
|
+ this.$message.info('地图缩小');
|
|
|
+ },
|
|
|
+
|
|
|
+ handleCenterRobot() {
|
|
|
+ // TODO: 实现居中到机器人
|
|
|
+ this.$message.info('居中到机器人');
|
|
|
+ },
|
|
|
+
|
|
|
+ handleToggleFullscreen() {
|
|
|
+ // TODO: 实现全屏切换
|
|
|
+ this.$message.info('全屏切换');
|
|
|
+ },
|
|
|
+
|
|
|
+ handleSaveMap() {
|
|
|
+ this.saveRoute();
|
|
|
+ },
|
|
|
+
|
|
|
+ // === 右侧面板事件处理 ===
|
|
|
+
|
|
|
+ // 添加当前点
|
|
|
+ handleAddCurrentPoint() {
|
|
|
+ this.addCurrentMapShow = true;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 元素选择
|
|
|
+ handleElementSelect(element) {
|
|
|
+ this.showInspector(element, 'edit');
|
|
|
+ // 在地图上选中该元素
|
|
|
+ this.$refs.olmap && this.$refs.olmap.selectShowEle && this.$refs.olmap.selectShowEle(element.id);
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // 编辑元素
|
|
|
+ handleElementEdit(element) {
|
|
|
+ this.showInspector(element, 'edit');
|
|
|
+ },
|
|
|
+
|
|
|
+ // 定位元素
|
|
|
+ handleElementLocate(element) {
|
|
|
+ this.$refs.olmap && this.$refs.olmap.selectShowEle && this.$refs.olmap.selectShowEle(element.id);
|
|
|
+ this.$message.success(`已定位到元素 ${element.id}`);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 删除元素
|
|
|
+ handleElementRemove(element) {
|
|
|
+ this.$confirm(`确定要删除元素 ${element.id} 吗?`, '确认删除', {
|
|
|
+ confirmButtonText: '确定',
|
|
|
+ cancelButtonText: '取消',
|
|
|
+ type: 'warning'
|
|
|
+ }).then(() => {
|
|
|
+ this.$refs.olmap && this.$refs.olmap.removeElement && this.$refs.olmap.removeElement(element.id);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ // 路网导出
|
|
|
+ handleNetworkExport() {
|
|
|
+ // 实际的导出逻辑应该在这里实现
|
|
|
+ setTimeout(() => {
|
|
|
+ try {
|
|
|
+ // TODO: 实现实际的路网导出逻辑
|
|
|
+ // 这里可以调用后端API或者生成文件下载
|
|
|
+ console.log('导出路网数据...');
|
|
|
+ // 成功后不需要再显示消息,因为RightPanel已经处理了
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error('路网导出失败:' + error.message);
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 路网导入
|
|
|
+ handleNetworkImport(type) {
|
|
|
+ // 实际的导入逻辑应该在这里实现
|
|
|
+ setTimeout(() => {
|
|
|
+ try {
|
|
|
+ const typeMap = {
|
|
|
+ 'import': '导入',
|
|
|
+ 'replace': '覆盖导入',
|
|
|
+ 'merge': '合并导入',
|
|
|
+ 'incremental': '增量导入'
|
|
|
+ };
|
|
|
+
|
|
|
+ // TODO: 实现实际的路网导入逻辑
|
|
|
+ // 这里可以调用后端API或者打开文件选择对话框
|
|
|
+ console.log(`${typeMap[type] || '导入'}路网数据...`, type);
|
|
|
+
|
|
|
+ // 根据不同类型执行不同的导入策略
|
|
|
+ switch (type) {
|
|
|
+ case 'import':
|
|
|
+ // 普通导入逻辑
|
|
|
+ break;
|
|
|
+ case 'replace':
|
|
|
+ // 覆盖导入:先清空现有数据,再导入新数据
|
|
|
+ break;
|
|
|
+ case 'merge':
|
|
|
+ // 合并导入:保留现有数据,添加新数据
|
|
|
+ break;
|
|
|
+ case 'incremental':
|
|
|
+ // 增量导入:只导入不存在的新元素
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 成功后不需要再显示消息,因为RightPanel已经处理了
|
|
|
+ } catch (error) {
|
|
|
+ this.$message.error(`路网${typeMap[type] || '导入'}失败:` + error.message);
|
|
|
+ }
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+
|
|
|
+ // === Inspector事件处理 ===
|
|
|
+
|
|
|
+ // 显示Inspector
|
|
|
+ showInspector(element, mode = 'edit') {
|
|
|
+ this.inspector.loading = true;
|
|
|
+ this.inspector.visible = true;
|
|
|
+ this.inspector.mode = mode;
|
|
|
+
|
|
|
+ // 模拟数据加载延迟
|
|
|
+ setTimeout(() => {
|
|
|
+ // 准备元素数据
|
|
|
+ const elementData = this.prepareElementData(element);
|
|
|
+ this.inspector.data = elementData;
|
|
|
+ this.inspector.loading = false;
|
|
|
+ this.currentFeature = element;
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 准备元素数据
|
|
|
+ prepareElementData(element) {
|
|
|
+ // 从resourcesFeature中获取完整的元素数据
|
|
|
+ const feature = this.resourcesFeature.find(f => f.getId() === element.id);
|
|
|
+ if (feature) {
|
|
|
+ const properties = feature.getProperties();
|
|
|
+ const geometry = feature.getGeometry();
|
|
|
+
|
|
|
+ // 合并基础信息和属性
|
|
|
+ return {
|
|
|
+ ...element,
|
|
|
+ ...properties,
|
|
|
+ type: geometry.getType(),
|
|
|
+ position: geometry.getType() === 'Point' ? geometry.getCoordinates() : undefined
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return element;
|
|
|
+ },
|
|
|
+
|
|
|
+ // Inspector编辑模式
|
|
|
+ handleInspectorEdit() {
|
|
|
+ this.inspector.mode = 'edit';
|
|
|
+ },
|
|
|
+
|
|
|
+ // Inspector保存
|
|
|
+ handleInspectorSave(elementData) {
|
|
|
+ // 更新资源特征对象
|
|
|
+ this.resourcesFeature.forEach(item => {
|
|
|
+ if (item.getId() == elementData.id) {
|
|
|
+ // 清理临时属性
|
|
|
+ const cleanData = { ...elementData };
|
|
|
+ delete cleanData.typeEle;
|
|
|
+ delete cleanData.directList;
|
|
|
+
|
|
|
+ item.setProperties(cleanData);
|
|
|
+
|
|
|
+ // 特殊处理:更新坐标
|
|
|
+ if (elementData.position && item.getGeometry().getType() === 'Point') {
|
|
|
+ item.getGeometry().setCoordinates(elementData.position);
|
|
|
+ // 通知地图组件更新点位坐标
|
|
|
+ this.$refs.olmap && this.$refs.olmap.pointPositionUpdate &&
|
|
|
+ this.$refs.olmap.pointPositionUpdate(elementData.id, elementData.position);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 特殊处理:如果是多边形,需要更新颜色
|
|
|
+ if (elementData.id.startsWith('s')) {
|
|
|
+ this.$refs.olmap && this.$refs.olmap.editSnapeColor && this.$refs.olmap.editSnapeColor(elementData.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 更新当前特征数据
|
|
|
+ this.currentFeature = { ...elementData };
|
|
|
+ this.haveDraw = true;
|
|
|
+
|
|
|
+ // 刷新右侧列表中的元素信息
|
|
|
+ this.updateElementInList(elementData);
|
|
|
+
|
|
|
+ // 关闭Inspector
|
|
|
+ this.inspector.visible = false;
|
|
|
+
|
|
|
+ // 在地图上保持选中状态
|
|
|
+ setTimeout(() => {
|
|
|
+ this.$refs.olmap && this.$refs.olmap.selectShowEle && this.$refs.olmap.selectShowEle(elementData.id);
|
|
|
+ }, 100);
|
|
|
+ },
|
|
|
+
|
|
|
+ // Inspector取消
|
|
|
+ handleInspectorCancel() {
|
|
|
+ this.inspector.visible = false;
|
|
|
+ this.inspector.mode = 'view';
|
|
|
+ },
|
|
|
+
|
|
|
+ // Inspector关闭
|
|
|
+ handleInspectorClose() {
|
|
|
+ this.inspector.visible = false;
|
|
|
+ this.inspector.mode = 'view';
|
|
|
+ this.inspector.data = null;
|
|
|
+ },
|
|
|
+
|
|
|
+ // Inspector定位
|
|
|
+ handleInspectorLocate(element) {
|
|
|
+ this.$refs.olmap && this.$refs.olmap.selectShowEle && this.$refs.olmap.selectShowEle(element.id);
|
|
|
+ // 可以添加地图缩放和居中逻辑
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ // Inspector高度变化
|
|
|
+ handleInspectorHeightChange(height) {
|
|
|
+ // 可以在这里处理高度变化后的布局调整
|
|
|
+ console.log('Inspector高度变化为:', height);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 更新元素列表中的元素信息
|
|
|
+ updateElementInList(elementData) {
|
|
|
+ const updateElementInArray = (array) => {
|
|
|
+ const index = array.findIndex(item => item.id === elementData.id);
|
|
|
+ if (index !== -1) {
|
|
|
+ array[index] = { ...array[index], ...elementData };
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 根据ID前缀更新对应数组
|
|
|
+ if (elementData.id.startsWith('p')) {
|
|
|
+ updateElementInArray(this.pointData);
|
|
|
+ } else if (elementData.id.startsWith('l')) {
|
|
|
+ updateElementInArray(this.lineData);
|
|
|
+ } else if (elementData.id.startsWith('b')) {
|
|
|
+ updateElementInArray(this.bowData);
|
|
|
+ } else if (elementData.id.startsWith('s')) {
|
|
|
+ updateElementInArray(this.shapeData);
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ // === 地图事件处理(保留原有逻辑)===
|
|
|
+
|
|
|
+ // 地图元素加载完毕的回执
|
|
|
+ elementRoadInitEnd(features) {
|
|
|
+ features.forEach(item => {
|
|
|
+ // 检查 item.values_ 和 item.values_.id 是否存在
|
|
|
+ if (item.values_ && item.values_.id) {
|
|
|
+ const id = item.values_.id;
|
|
|
+ const data = {
|
|
|
+ id: id,
|
|
|
+ name: item.values_.name,
|
|
|
+ type: item.getGeometry().getType()
|
|
|
+ };
|
|
|
+ // 根据 id 前缀分类存入对应数组
|
|
|
+ if (id.startsWith('p')) {
|
|
|
+ this.pointData.push(data);
|
|
|
+ } else if (id.startsWith('l')) {
|
|
|
+ this.lineData.push(data);
|
|
|
+ } else if (id.startsWith('b')) {
|
|
|
+ this.bowData.push(data);
|
|
|
+ } else if (id.startsWith('s')) {
|
|
|
+ this.shapeData.push(data);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 对分类后的数组按数字部分排序
|
|
|
+ this.pointData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
+ this.lineData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
+ this.bowData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
+ this.shapeData.sort((a, b) => parseInt(a.id.split('_')[1]) - parseInt(b.id.split('_')[1]));
|
|
|
+ this.resourcesFeature = features;
|
|
|
+ },
|
|
|
+ // 某个元素绘制完成的回调
|
|
|
+ elementRoadDrawEnd(feature) {
|
|
|
+ const id = feature.values_.id || feature.getId();
|
|
|
+ const data = {
|
|
|
+ id: id,
|
|
|
+ name: feature.values_.name,
|
|
|
+ type: feature.getGeometry().getType()
|
|
|
+ };
|
|
|
+ if (id.startsWith('p')) {
|
|
|
+ this.pointData.push(data);
|
|
|
+ // 按照类型为feature初始化基础参数和高级参数(点)
|
|
|
+ this.initElelmentParamsPonint(feature);
|
|
|
+ } else if (id.startsWith('l')) {
|
|
|
+ this.lineData.push(data);
|
|
|
+ // 按照类型为feature初始化基础参数和高级参数(线)
|
|
|
+ this.initElelmentParamsBowOrLine(feature);
|
|
|
+ } else if (id.startsWith('b')) {
|
|
|
+ this.bowData.push(data);
|
|
|
+ // 按照类型为feature初始化基础参数和高级参数(曲线)
|
|
|
+ this.initElelmentParamsBowOrLine(feature);
|
|
|
+ } else if (id.startsWith('s')) {
|
|
|
+ this.shapeData.push(data);
|
|
|
+ // 按照类型为feature初始化基础参数和高级参数(面)
|
|
|
+ this.initElelmentParamsSnape(feature);
|
|
|
+ }
|
|
|
+ // 标记当前存在绘制的操作,拦截使用
|
|
|
+ this.haveDraw = true; // 是否操作过页面元素(新增修改或者删除元素) (在切换页面或者刷新时进行拦截,避免误操作退出页面)
|
|
|
+ },
|
|
|
+ // 查看某个元素
|
|
|
+ watchEle(id) {
|
|
|
+ // 调用地图组件显示元素
|
|
|
+ this.$refs.olmap.selectShowEle(id);
|
|
|
+ },
|
|
|
+ // 查看某个元素的子组件回调
|
|
|
+ selectShowEleResult(feature) {
|
|
|
+ const geometry = feature.getGeometry();
|
|
|
+ console.log(geometry.getCoordinates());
|
|
|
+
|
|
|
+ if (geometry.getType() == 'Point') {
|
|
|
+ // 如果是点位则临时保存xyz和类型到参数用于渲染(保存时会移除) 注:保存元素坐标为参数用于对应表单数据,否则需要用方法获取,无法双向绑定
|
|
|
+ feature.set('position', geometry.getCoordinates())
|
|
|
+ } else if (geometry.getType() == "LineString") {
|
|
|
+ // 解析线段类型的direct参数用于渲染和修改(保存时需要渲染回原始数据模式,切记)
|
|
|
+ const value = feature.values_.direct - 100 || 0;
|
|
|
+ const binary = value.toString(2).padStart(4, '0');
|
|
|
+ const result = [
|
|
|
+ binary[0] === '1', // bit3
|
|
|
+ binary[1] === '1', // bit2
|
|
|
+ binary[2] === '1', // bit1
|
|
|
+ binary[3] === '1' // bit0
|
|
|
+ ];
|
|
|
+ // 临时参数渲染使用, 保存时会删除
|
|
|
+ feature.set('directList', result);
|
|
|
+ }
|
|
|
+ // 临时保存类型到参数用于渲染(保存时回移除)
|
|
|
+ feature.set('typeEle', geometry.getType())
|
|
|
+
|
|
|
+ // 准备元素数据并显示Inspector
|
|
|
+ const elementData = {
|
|
|
+ id: feature.getId(),
|
|
|
+ name: feature.get('name') || '',
|
|
|
+ type: geometry.getType(),
|
|
|
+ ...feature.getProperties()
|
|
|
+ };
|
|
|
+
|
|
|
+ this.showInspector(elementData, 'edit');
|
|
|
+ },
|
|
|
+ // 移除某个元素
|
|
|
+ removeElement(id) {
|
|
|
+ // 调用地图组件移除元素
|
|
|
+ this.$refs.olmap.removeElement(id);
|
|
|
+ },
|
|
|
+ // 移除元素操作的回调
|
|
|
+ removeElementResult(id) {
|
|
|
+ if (!id) {
|
|
|
+ this.$message.error('移除元素失败!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 删除当前数据table中这个元素
|
|
|
+ if (id.startsWith('p')) {
|
|
|
+ const index = this.pointData.findIndex(item => item.id === id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.pointData.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (id.startsWith('l')) {
|
|
|
+ const index = this.lineData.findIndex(item => item.id === id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.lineData.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (id.startsWith('b')) {
|
|
|
+ const index = this.bowData.findIndex(item => item.id === id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.bowData.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (id.startsWith('s')) {
|
|
|
+ const index = this.shapeData.findIndex(item => item.id === id);
|
|
|
+ if (index !== -1) {
|
|
|
+ this.shapeData.splice(index, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 判断当前选择元素是否被删除,如果是则删除
|
|
|
+ if (this.currentFeature && this.currentFeature.id == id) {
|
|
|
+ this.currentFeature = {};
|
|
|
+ }
|
|
|
+ // 删除源features中的此元素
|
|
|
+ const index = this.resourcesFeature.findIndex(feature => feature.getId() == id);
|
|
|
+ // 如果找到了该元素,则删除
|
|
|
+ if (index !== -1) {
|
|
|
+ this.resourcesFeature.splice(index, 1);
|
|
|
+ }
|
|
|
+ this.haveDraw = true;
|
|
|
+ },
|
|
|
+ // 初始化点位元素基础和高级参数
|
|
|
+ initElelmentParamsPonint(feature) {
|
|
|
+ feature.set('name', '');
|
|
|
+ feature.set('yaw', 0); // 弧度
|
|
|
+ // 如果是通过实时位姿则需要判断是否有值,有则设置
|
|
|
+ feature.set('isyawfix', feature.get('isyawfix') ? true : false); // 偏航使能
|
|
|
+ feature.set('taskid', 0);
|
|
|
+ feature.set('offset', 0);
|
|
|
+ feature.set('pitch', 0)
|
|
|
+ feature.set('roll', 0)
|
|
|
+ this.resourcesFeature.push(feature);
|
|
|
+ },
|
|
|
+ // 初始化执行元素基础和高级参数
|
|
|
+ initElelmentParamsBowOrLine(feature) {
|
|
|
+ feature.set('name', '');
|
|
|
+ // direct中的值首先需要减去100,结果的后4位bit位分别代表如下含义:
|
|
|
+ // bit3:为1时,表示允许车辆从起点行驶到终点,且机器人以正常前行的方式行驶;
|
|
|
+ // bit2:为1时,表示允许车辆从起点行驶到终点,且机器人以倒车的方式行驶;
|
|
|
+ // bit1:为1时,表示允许车辆从终点行驶到起点,且机器人以正常前行的方式行驶;
|
|
|
+ // bit0:为1时,表示允许车辆从终点行驶到起点,且机器人以倒车的方式行驶。
|
|
|
+ // 举例: direct=105(bit2和bit0为1),表示为双向车道,但是不论机器人从起点前往终点,还是从终点前往起点,都会以倒车的方式行驶。
|
|
|
+ feature.set('direct', 110); // 常用 110:起点至终点 + 终点至起点(双方向) 正向行驶 108:起点至终点 正向行驶
|
|
|
+ feature.set('maxspeed', 8) // 最大限速 m/s
|
|
|
+ feature.set('minspeed', 0) // 最小限速 m/s
|
|
|
+ feature.set('lanewidth', 1) // 车道宽度
|
|
|
+ feature.set('leftlanenum', 0) //前进方向左侧车道数
|
|
|
+ feature.set('rightlanenum', 0) //前进方向右侧车道数
|
|
|
+ feature.set('obstype', 0) // 避障方式,0:停车等待,1:车道绕障,2:路网绕障,默认为0
|
|
|
+ feature.set('obsvalue', 200) // 障碍物参数(例如:权重值或影响范围)
|
|
|
+ feature.set('followdis', 0.4) // 跟随距离
|
|
|
+ feature.set('runtype', 0) // 运行类型
|
|
|
+ feature.set('selftheta', 0.5) // 自身角度
|
|
|
+ feature.set('xytolerance', 0.2) // 平面坐标容差
|
|
|
+ feature.set('s2eforward', 0) // 机器人沿当前线段从起点到达终点时多行驶(负数则为少行驶)的距离,单位为米,默认为0
|
|
|
+ feature.set('e2sforward', 0) // 机器人沿当前线段从终点到达起点时多行驶的距离,单位为米,默认为0
|
|
|
+ feature.set('thtolerance', 0) // 角度容差
|
|
|
+ feature.set('mintheta', 0) // 最小转向角
|
|
|
+ feature.set('maxtheta', 1) // 最大转向角
|
|
|
+
|
|
|
+ this.resourcesFeature.push(feature);
|
|
|
+ },
|
|
|
+ // 初始化面元素基础和高级参数
|
|
|
+ initElelmentParamsSnape(feature) {
|
|
|
+ feature.set('name', '');
|
|
|
+ feature.set('typeEle', feature.getGeometry().getType()); // 保存元素类型为参数用于动态绑定对应的元素修改表单,否则需要用方法获取
|
|
|
+ feature.set('color', "#7EFFFA");
|
|
|
+ //区域类型,说明: 0:隔离区域,限定机器人只能在该区域活动;1:装饰区域,仅人机交互用,不影响导航;
|
|
|
+ // 2:禁行区域,不允许机器人进入该区域;3:会车管制区,特定场景使用;
|
|
|
+ // 4:道闸管控区,特定场景使用;11:GPS定位区,进入该区域后,从激光定位切换到GPS定位;
|
|
|
+ // 22:动态禁行区,特定场景使用。
|
|
|
+ feature.set('type', 1);
|
|
|
+ feature.set('transparent', 200);
|
|
|
+ this.resourcesFeature.push(feature);
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 点位坐标修改
|
|
|
+ */
|
|
|
+ positionEdit() {
|
|
|
+ this.haveDraw = true;
|
|
|
+ this.$refs.olmap.pointPositionUpdate(this.currentFeature.id, this.currentFeature.position);
|
|
|
+ },
|
|
|
+ // 自定义参数修改提交
|
|
|
+ setProperties() {
|
|
|
+ if (!this.currentFeature) return;
|
|
|
+ this.resourcesFeature.forEach(item => {
|
|
|
+ if (item.getId() == this.currentFeature.id) {
|
|
|
+ // 额外参数处理 线
|
|
|
+ if (this.currentFeature.id.startsWith('l') || this.currentFeature.id.startsWith('b')) {
|
|
|
+ // direct还原
|
|
|
+ let directList = this.currentFeature.directList;
|
|
|
+ // 将布尔集合转成4位bit集合, 再转成10进制, 加100还原成原始报文
|
|
|
+ const binaryString = directList.map(bit => (bit ? '1' : '0')).join('');
|
|
|
+ const value = parseInt(binaryString, 2);
|
|
|
+ const direct = value + 100;
|
|
|
+ this.currentFeature.direct = direct;
|
|
|
+ }
|
|
|
+ // 处理完毕后先刷新对象到画布
|
|
|
+ item.setProperties(this.currentFeature)
|
|
|
+ // 刷新完毕后用自定义参数处理其他需要修改完毕能看到的元素效果(例如修改name或者图形颜色等)
|
|
|
+ if (this.currentFeature.id.startsWith('s')) {
|
|
|
+ // 额外处理多边形的效果
|
|
|
+ // 1. 修改图形的颜色,文本
|
|
|
+ this.$refs.olmap.editSnapeColor(this.currentFeature.id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.haveDraw = true; // 是否操作过页面元素(新增修改或者删除元素) (在切换页面或者刷新时进行拦截,避免误操作退出页面)
|
|
|
+ },
|
|
|
+ // 保存路网
|
|
|
+ saveRoute() {
|
|
|
+ // 保存时清理当前所有对象的额外渲染参数
|
|
|
+ this.resourcesFeature.forEach(feature => {
|
|
|
+ const values = feature.getProperties(); // 获取feature的values_自定义属性
|
|
|
+ // 检查并删除特定的属性(如果存在)
|
|
|
+ if (values) {
|
|
|
+ if (values.hasOwnProperty('typeEle')) {
|
|
|
+ delete values.typeEle; // 删除 typeEle 属性
|
|
|
+ }
|
|
|
+ if (values.hasOwnProperty('position')) {
|
|
|
+ delete values.position; // 删除 position 属性
|
|
|
+ }
|
|
|
+ if (values.hasOwnProperty('directList')) {
|
|
|
+ delete values.directList; // 删除 directList 属性
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // === 添加当前点对话框处理 ===
|
|
|
+
|
|
|
+ // 打开添加当前点对话框
|
|
|
+ openCurrentToMapDialog() {
|
|
|
+ this.currentRobotRecord = {
|
|
|
+ x: this.robotPoseData.x || 0,
|
|
|
+ y: this.robotPoseData.y || 0,
|
|
|
+ z: 0,
|
|
|
+ angle: this.robotPoseData.angle || 0,
|
|
|
+ angleEnable: false
|
|
|
+ };
|
|
|
+ },
|
|
|
+
|
|
|
+ // 添加当前点到地图
|
|
|
+ addCurrentToMap() {
|
|
|
+ this.$refs.currentPointForm.validate((valid) => {
|
|
|
+ if (valid) {
|
|
|
+ this.addCurrentMapShow = false;
|
|
|
+ // 使用组件的根据坐标绘制点方法
|
|
|
+ const data = [
|
|
|
+ { yaw: this.currentRobotRecord.angle },
|
|
|
+ { isyawfix: this.currentRobotRecord.angleEnable }
|
|
|
+ ];
|
|
|
+ this.$refs.olmap && this.$refs.olmap.createPointAtCoordinate &&
|
|
|
+ this.$refs.olmap.createPointAtCoordinate(
|
|
|
+ [this.currentRobotRecord.x, this.currentRobotRecord.y, this.currentRobotRecord.z || 0],
|
|
|
+ '',
|
|
|
+ data
|
|
|
+ );
|
|
|
+ this.$message.success('已添加当前位姿点到地图');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+@import './components/shared/_map-shared.scss';
|
|
|
+
|
|
|
+.edit-page {
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background: #f5f7fa;
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ /* CSS变量:定义安全区域 */
|
|
|
+ --left-safe: 88px; /* 左边工具栏+内边距的安全距离 */
|
|
|
+ --right-panel-width: 380px; /* 右侧面板宽度,由JS动态更新 */
|
|
|
+ --right-gutter: 32px; /* 右侧间隙 */
|
|
|
+ --right-safe: calc(var(--right-panel-width) + var(--right-gutter));
|
|
|
+}
|
|
|
+
|
|
|
+.map-container {
|
|
|
+ flex: 1;
|
|
|
+ display: flex;
|
|
|
+ position: relative;
|
|
|
+ min-height: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.toolbar-container {
|
|
|
+ position: absolute;
|
|
|
+ top: 16px;
|
|
|
+ left: 16px;
|
|
|
+ z-index: $map-z-index-toolbar;
|
|
|
+ pointer-events: none;
|
|
|
+
|
|
|
+ > * {
|
|
|
+ pointer-events: auto;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#map-stage {
|
|
|
+ flex: 1;
|
|
|
+ position: relative; /* 让子元素 absolute 以此为参照 */
|
|
|
+ background: #f5f5f5;
|
|
|
+ overflow: hidden; /* 防止子元素视觉溢出 */
|
|
|
+}
|
|
|
+
|
|
|
+.panel-container {
|
|
|
+ // 编辑页面板现在使用 fixed 定位,容器不需要特殊样式
|
|
|
+ pointer-events: none;
|
|
|
+
|
|
|
+ > * {
|
|
|
+ pointer-events: auto;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 对话框样式优化
|
|
|
+:deep(.el-dialog) {
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
|
|
|
+
|
|
|
+ .el-dialog__header {
|
|
|
+ padding: 20px 24px 10px;
|
|
|
+ border-bottom: 1px solid #e4e7ed;
|
|
|
+
|
|
|
+ .el-dialog__title {
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dialog__body {
|
|
|
+ padding: 20px 24px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dialog__footer {
|
|
|
+ padding: 10px 24px 20px;
|
|
|
+ text-align: right;
|
|
|
+
|
|
|
+ .el-button {
|
|
|
+ margin-left: 12px;
|
|
|
+
|
|
|
+ &:first-child {
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 表单样式优化
|
|
|
+:deep(.el-form) {
|
|
|
+ .el-form-item {
|
|
|
+ margin-bottom: 18px;
|
|
|
+
|
|
|
+ .el-form-item__label {
|
|
|
+ font-weight: 500;
|
|
|
+ color: #374151;
|
|
|
+ line-height: 1.6;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item__content {
|
|
|
+ line-height: 1.6;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input {
|
|
|
+ .el-input__inner {
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #d1d5db;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #3b82f6;
|
|
|
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-input-number {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .el-input__inner {
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #d1d5db;
|
|
|
+ text-align: left;
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #3b82f6;
|
|
|
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-switch {
|
|
|
+ .el-switch__core {
|
|
|
+ border-radius: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 响应式适配
|
|
|
+@media (max-width: 1200px) {
|
|
|
+ .panel-container {
|
|
|
+ right: 8px;
|
|
|
+ top: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .toolbar-container {
|
|
|
+ left: 8px;
|
|
|
+ top: 8px;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media (max-width: 768px) {
|
|
|
+ .edit-page {
|
|
|
+ .map-container {
|
|
|
+ flex-direction: column;
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-container {
|
|
|
+ position: relative;
|
|
|
+ top: auto;
|
|
|
+ right: auto;
|
|
|
+ width: 100%;
|
|
|
+ z-index: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ .toolbar-container {
|
|
|
+ position: relative;
|
|
|
+ top: auto;
|
|
|
+ left: auto;
|
|
|
+ z-index: auto;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 暗色主题适配
|
|
|
+html.dark {
|
|
|
+ .edit-page {
|
|
|
+ background: #1f2937;
|
|
|
+
|
|
|
+ .map-content {
|
|
|
+ background: #374151;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 动画效果
|
|
|
+@keyframes fadeInUp {
|
|
|
+ from {
|
|
|
+ opacity: 0;
|
|
|
+ transform: translateY(20px);
|
|
|
+ }
|
|
|
+ to {
|
|
|
+ opacity: 1;
|
|
|
+ transform: translateY(0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.edit-page {
|
|
|
+ animation: fadeInUp 0.3s ease-out;
|
|
|
+}
|
|
|
+
|
|
|
+/* === 添加当前点弹框样式(参考导航页目标点编辑弹框) === */
|
|
|
+/* 全局弹框居中样式 */
|
|
|
+.centered-dialog {
|
|
|
+ display: flex !important;
|
|
|
+ align-items: center !important;
|
|
|
+ justify-content: center !important;
|
|
|
+}
|
|
|
+
|
|
|
+.add-pose-dialog {
|
|
|
+ ::v-deep .el-dialog {
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
|
|
|
+ margin: 0 auto;
|
|
|
+ position: relative;
|
|
|
+ top: 50%;
|
|
|
+ transform: translateY(-50%);
|
|
|
+ max-height: 90vh;
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 确保弹框在页面中居中 */
|
|
|
+ ::v-deep .el-dialog__wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-height: 100vh;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 移除默认的margin-top */
|
|
|
+ ::v-deep .el-dialog {
|
|
|
+ margin-top: 0 !important;
|
|
|
+ margin-bottom: 0 !important;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-dialog__header {
|
|
|
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
|
+ padding: 20px 24px;
|
|
|
+ margin: 0;
|
|
|
+ border-radius: 12px 12px 0 0;
|
|
|
+
|
|
|
+ .el-dialog__title {
|
|
|
+ color: white;
|
|
|
+ font-size: 18px;
|
|
|
+ font-weight: 600;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-dialog__close {
|
|
|
+ color: white;
|
|
|
+ font-size: 18px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ color: #f0f0f0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-dialog__body {
|
|
|
+ padding: 24px;
|
|
|
+ background: #f8fafc;
|
|
|
+ margin: 0;
|
|
|
+ max-height: calc(90vh - 120px);
|
|
|
+ overflow-y: auto;
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-dialog__footer {
|
|
|
+ padding: 16px 24px 24px;
|
|
|
+ background: #f8fafc;
|
|
|
+ border-top: 1px solid #e2e8f0;
|
|
|
+ border-radius: 0 0 12px 12px;
|
|
|
+ margin: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.pose-form {
|
|
|
+ .el-form-item {
|
|
|
+ margin-bottom: 14px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item__content {
|
|
|
+ flex: 1;
|
|
|
+ margin-left: 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .coordinate-input {
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .el-form-item__label {
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2d3748;
|
|
|
+ padding-right: 12px;
|
|
|
+ min-width: 100px;
|
|
|
+ font-size: 14px;
|
|
|
+ line-height: 44px;
|
|
|
+ height: 44px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .coordinate-input {
|
|
|
+ ::v-deep .el-input__inner {
|
|
|
+ border-radius: 8px;
|
|
|
+ border: 1px solid #e2e8f0;
|
|
|
+ height: 44px;
|
|
|
+ font-size: 15px;
|
|
|
+ padding: 0 16px;
|
|
|
+ background: #ffffff;
|
|
|
+ transition: all 0.2s ease;
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #667eea;
|
|
|
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
|
|
|
+ background: #fafbff;
|
|
|
+ }
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ border-color: #cbd5e0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ::v-deep .el-input-number {
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .el-input__inner {
|
|
|
+ border-radius: 6px;
|
|
|
+ border: 1px solid #e2e8f0;
|
|
|
+ height: 40px;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 0 12px;
|
|
|
+
|
|
|
+ &:focus {
|
|
|
+ border-color: #667eea;
|
|
|
+ box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.dialog-content {
|
|
|
+ .form-section {
|
|
|
+ background: white;
|
|
|
+ border-radius: 10px;
|
|
|
+ padding: 20px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
|
+ border: 1px solid #f1f5f9;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin: 0 0 16px 0;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #2d3748;
|
|
|
+ border-bottom: 2px solid #e2e8f0;
|
|
|
+ padding-bottom: 8px;
|
|
|
+
|
|
|
+ i {
|
|
|
+ margin-right: 10px;
|
|
|
+ color: #667eea;
|
|
|
+ font-size: 18px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
</style>
|