Commit 24f8cd2dff6a9300dc428bf02e041cbfbb170d4e
Merge branch 'master' of http://39.98.150.180/antissoft/lvqianmeiye_ERP
Showing
1 changed file
with
700 additions
and
240 deletions
antis-ncc-admin/src/views/lqMdxx/Form.vue
| 1 | -<template> | ||
| 2 | - <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情':'编辑'" :close-on-click-modal="false" :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="600px"> | ||
| 3 | - <el-row :gutter="15" class="" > | ||
| 4 | - <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" :disabled="!!isDetail" :rules="rules"> | ||
| 5 | - <el-col :span="24" v-if="false" > | ||
| 6 | - <el-form-item label="主键" prop="id"> | ||
| 7 | - <el-input v-model="dataForm.id" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 8 | - </el-input> | ||
| 9 | - </el-form-item> | ||
| 10 | - </el-col> | ||
| 11 | - <el-col :span="24"> | ||
| 12 | - <el-form-item label="门店编码" prop="mdbm"> | ||
| 13 | - <el-input v-model="dataForm.mdbm" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 14 | - </el-input> | ||
| 15 | - </el-form-item> | ||
| 16 | - </el-col> | ||
| 17 | - <el-col :span="24"> | ||
| 18 | - <el-form-item label="单据门店编号" prop="djmdbh"> | ||
| 19 | - <el-input v-model="dataForm.djmdbh" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 20 | - </el-input> | ||
| 21 | - </el-form-item> | ||
| 22 | - </el-col> | ||
| 23 | - <el-col :span="24"> | ||
| 24 | - <el-form-item label="单据门店" prop="djmd"> | ||
| 25 | - <el-input v-model="dataForm.djmd" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 26 | - </el-input> | ||
| 27 | - </el-form-item> | ||
| 28 | - </el-col> | ||
| 29 | - <el-col :span="24"> | ||
| 30 | - <el-form-item label="店名" prop="dm"> | ||
| 31 | - <el-input v-model="dataForm.dm" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 32 | - </el-input> | ||
| 33 | - </el-form-item> | ||
| 34 | - </el-col> | ||
| 35 | - <el-col :span="24"> | ||
| 36 | - <el-form-item label="城市" prop="cs"> | ||
| 37 | - <el-input v-model="dataForm.cs" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 38 | - </el-input> | ||
| 39 | - </el-form-item> | ||
| 40 | - </el-col> | ||
| 41 | - <el-col :span="24"> | ||
| 42 | - <el-form-item label="地址" prop="dz"> | ||
| 43 | - <el-input v-model="dataForm.dz" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 44 | - </el-input> | ||
| 45 | - </el-form-item> | ||
| 46 | - </el-col> | ||
| 47 | - <el-col :span="24"> | ||
| 48 | - <el-form-item label="姓名" prop="xm"> | ||
| 49 | - <el-input v-model="dataForm.xm" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 50 | - </el-input> | ||
| 51 | - </el-form-item> | ||
| 52 | - </el-col> | ||
| 53 | - <el-col :span="24"> | ||
| 54 | - <el-form-item label="电话号码" prop="dhhm"> | ||
| 55 | - <el-input v-model="dataForm.dhhm" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 56 | - </el-input> | ||
| 57 | - </el-form-item> | ||
| 58 | - </el-col> | ||
| 59 | - <el-col :span="24"> | ||
| 60 | - <el-form-item label="座机" prop="zj"> | ||
| 61 | - <el-input v-model="dataForm.zj" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 62 | - </el-input> | ||
| 63 | - </el-form-item> | ||
| 64 | - </el-col> | ||
| 65 | - <el-col :span="24"> | ||
| 66 | - <el-form-item label="开业时间" prop="kysj"> | ||
| 67 | - <el-date-picker v-model="dataForm.kysj" placeholder="请选择" clearable :style='{"width":"100%"}' type='date' format="yyyy-MM-dd" value-format="timestamp" > | ||
| 68 | - </el-date-picker> | ||
| 69 | - </el-form-item> | ||
| 70 | - </el-col> | ||
| 71 | - <el-col :span="24"> | ||
| 72 | - <el-form-item label="最新状态" prop="zxzt"> | ||
| 73 | - <el-select v-model="dataForm.zxzt" placeholder="请选择" clearable :style='{"width":"100%"}' > | ||
| 74 | - <el-option v-for="(item, index) in zxztOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option> | ||
| 75 | - </el-select> | ||
| 76 | - </el-form-item> | ||
| 77 | - </el-col> | ||
| 78 | - <el-col :span="24"> | ||
| 79 | - <el-form-item label="工商名称" prop="gsmc"> | ||
| 80 | - <el-input v-model="dataForm.gsmc" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 81 | - </el-input> | ||
| 82 | - </el-form-item> | ||
| 83 | - </el-col> | ||
| 84 | - <el-col :span="24"> | ||
| 85 | - <el-form-item label="法人" prop="fr"> | ||
| 86 | - <el-input v-model="dataForm.fr" placeholder="请输入" clearable :style='{"width":"100%"}' > | ||
| 87 | - </el-input> | ||
| 88 | - </el-form-item> | ||
| 89 | - </el-col> | ||
| 90 | - <el-col :span="24"> | ||
| 91 | - <el-form-item label="有无社保" prop="ywsb"> | ||
| 92 | - <el-select v-model="dataForm.ywsb" placeholder="请选择" clearable :style='{"width":"100%"}' > | ||
| 93 | - <el-option v-for="(item, index) in ywsbOptions" :key="index" :label="item.fullName" :value="item.id" ></el-option> | ||
| 94 | - </el-select> | ||
| 95 | - </el-form-item> | ||
| 96 | - </el-col> | ||
| 97 | - <el-col :span="24"> | ||
| 98 | - <el-form-item label="在职人数" prop="zzrs"> | ||
| 99 | - <el-input-number v-model="dataForm.zzrs" :min="0" :step="1" :precision="0" placeholder="请输入" :style='{"width":"100%"}' /> | ||
| 100 | - </el-form-item> | ||
| 101 | - </el-col> | ||
| 102 | - <el-col :span="24"> | ||
| 103 | - <el-form-item label="门店类别" prop="storeCategory"> | ||
| 104 | - <el-select v-model="dataForm.storeCategory" placeholder="请选择" clearable :style='{"width":"100%"}' > | ||
| 105 | - <el-option v-for="(item, index) in storeCategoryOptions" :key="index" :label="item.Name" :value="item.Value" ></el-option> | ||
| 106 | - </el-select> | ||
| 107 | - </el-form-item> | ||
| 108 | - </el-col> | ||
| 109 | - <el-col :span="24"> | ||
| 110 | - <el-form-item label="门店类型" prop="storeType"> | ||
| 111 | - <el-select v-model="dataForm.storeType" placeholder="请选择" clearable :style='{"width":"100%"}' > | ||
| 112 | - <el-option v-for="(item, index) in storeTypeOptions" :key="index" :label="item.Name" :value="item.Value" ></el-option> | ||
| 113 | - </el-select> | ||
| 114 | - </el-form-item> | ||
| 115 | - </el-col> | ||
| 116 | - </el-form> | 1 | +<template> |
| 2 | + <el-dialog :title="!dataForm.id ? '新建' : isDetail ? '详情' : '编辑'" :close-on-click-modal="false" | ||
| 3 | + :visible.sync="visible" class="NCC-dialog NCC-dialog_center" lock-scroll width="720px"> | ||
| 4 | + <el-row :gutter="15"> | ||
| 5 | + <el-form ref="elForm" :model="dataForm" size="small" label-width="100px" label-position="right" | ||
| 6 | + :disabled="!!isDetail" :rules="rules"> | ||
| 7 | + <!-- 基础信息字段 --> | ||
| 8 | + <el-col :span="24" v-if="false"> | ||
| 9 | + <el-form-item label="主键" prop="id"> | ||
| 10 | + <el-input v-model="dataForm.id" /> | ||
| 11 | + </el-form-item> | ||
| 12 | + </el-col> | ||
| 13 | + <el-col :span="12"> | ||
| 14 | + <el-form-item label="门店编码" prop="mdbm"> | ||
| 15 | + <el-input v-model="dataForm.mdbm" placeholder="请输入" clearable /> | ||
| 16 | + </el-form-item> | ||
| 17 | + </el-col> | ||
| 18 | + <el-col :span="12"> | ||
| 19 | + <el-form-item label="店名" prop="dm"> | ||
| 20 | + <el-input v-model="dataForm.dm" placeholder="请输入" clearable /> | ||
| 21 | + </el-form-item> | ||
| 22 | + </el-col> | ||
| 23 | + <el-col :span="24"> | ||
| 24 | + <el-form-item label="地址" prop="dz"> | ||
| 25 | + <el-input v-model="dataForm.dz" placeholder="请输入完整地址" clearable> | ||
| 26 | + <el-button slot="append" icon="el-icon-location-outline" | ||
| 27 | + @click="handleOpenLocation">地图定位</el-button> | ||
| 28 | + </el-input> | ||
| 29 | + </el-form-item> | ||
| 30 | + </el-col> | ||
| 31 | + <el-col :span="12"> | ||
| 32 | + <el-form-item label="经度" prop="longitude"> | ||
| 33 | + <el-input v-model="dataForm.longitude" readonly placeholder="请通过地图定位选择" /> | ||
| 34 | + </el-form-item> | ||
| 35 | + </el-col> | ||
| 36 | + <el-col :span="12"> | ||
| 37 | + <el-form-item label="纬度" prop="latitude"> | ||
| 38 | + <el-input v-model="dataForm.latitude" readonly placeholder="请通过地图定位选择" /> | ||
| 39 | + </el-form-item> | ||
| 40 | + </el-col> | ||
| 41 | + <el-col :span="24"> | ||
| 42 | + <el-form-item label="电子围栏"> | ||
| 43 | + <div class="fence-status-bar"> | ||
| 44 | + <el-tag :type="dataForm.fencePolygons && dataForm.fencePolygons.length ? 'success' : 'info'" | ||
| 45 | + size="medium"> | ||
| 46 | + {{ (dataForm.fencePolygons && dataForm.fencePolygons.length) ? '已设置围栏 (1块)' : '未设置围栏' }} | ||
| 47 | + </el-tag> | ||
| 48 | + <el-button type="primary" size="mini" icon="el-icon-edit" style="margin-left: 10px" | ||
| 49 | + :disabled="!dataForm.longitude || !dataForm.latitude" @click="handleOpenFence"> | ||
| 50 | + 设置围栏 | ||
| 51 | + </el-button> | ||
| 52 | + <span v-if="!dataForm.longitude" class="hint-text">(请先完成地图定位)</span> | ||
| 53 | + </div> | ||
| 54 | + </el-form-item> | ||
| 55 | + </el-col> | ||
| 56 | + | ||
| 57 | + <!-- 其他业务字段 --> | ||
| 58 | + <el-col :span="12"> | ||
| 59 | + <el-form-item label="城市" prop="cs"> | ||
| 60 | + <el-input v-model="dataForm.cs" placeholder="请输入" clearable /> | ||
| 61 | + </el-form-item> | ||
| 62 | + </el-col> | ||
| 63 | + <el-col :span="12"> | ||
| 64 | + <el-form-item label="最新状态" prop="zxzt"> | ||
| 65 | + <el-select v-model="dataForm.zxzt" placeholder="请选择" clearable :style='{ "width": "100%" }'> | ||
| 66 | + <el-option v-for="(item, index) in zxztOptions" :key="index" :label="item.fullName" | ||
| 67 | + :value="item.id"></el-option> | ||
| 68 | + </el-select> | ||
| 69 | + </el-form-item> | ||
| 70 | + </el-col> | ||
| 71 | + <el-col :span="12"> | ||
| 72 | + <el-form-item label="门店类别" prop="storeCategory"> | ||
| 73 | + <el-select v-model="dataForm.storeCategory" placeholder="请选择" clearable | ||
| 74 | + :style='{ "width": "100%" }'> | ||
| 75 | + <el-option v-for="(item, index) in storeCategoryOptions" :key="index" :label="item.Name" | ||
| 76 | + :value="item.Value"></el-option> | ||
| 77 | + </el-select> | ||
| 78 | + </el-form-item> | ||
| 79 | + </el-col> | ||
| 80 | + <el-col :span="12"> | ||
| 81 | + <el-form-item label="门店类型" prop="storeType"> | ||
| 82 | + <el-select v-model="dataForm.storeType" placeholder="请选择" clearable | ||
| 83 | + :style='{ "width": "100%" }'> | ||
| 84 | + <el-option v-for="(item, index) in storeTypeOptions" :key="index" :label="item.Name" | ||
| 85 | + :value="item.Value"></el-option> | ||
| 86 | + </el-select> | ||
| 87 | + </el-form-item> | ||
| 88 | + </el-col> | ||
| 89 | + <el-col :span="12"> | ||
| 90 | + <el-form-item label="姓名" prop="xm"> | ||
| 91 | + <el-input v-model="dataForm.xm" placeholder="请输入" clearable /> | ||
| 92 | + </el-form-item> | ||
| 93 | + </el-col> | ||
| 94 | + <el-col :span="12"> | ||
| 95 | + <el-form-item label="电话号码" prop="dhhm"> | ||
| 96 | + <el-input v-model="dataForm.dhhm" placeholder="请输入" clearable /> | ||
| 97 | + </el-form-item> | ||
| 98 | + </el-col> | ||
| 99 | + </el-form> | ||
| 117 | </el-row> | 100 | </el-row> |
| 118 | <span slot="footer" class="dialog-footer"> | 101 | <span slot="footer" class="dialog-footer"> |
| 119 | <el-button @click="visible = false">取 消</el-button> | 102 | <el-button @click="visible = false">取 消</el-button> |
| 120 | <el-button type="primary" @click="dataFormSubmit()" v-if="!isDetail">确 定</el-button> | 103 | <el-button type="primary" @click="dataFormSubmit()" v-if="!isDetail">确 定</el-button> |
| 121 | </span> | 104 | </span> |
| 105 | + | ||
| 106 | + <!-- 定位弹窗 --> | ||
| 107 | + <el-dialog title="门店地图定位" :visible.sync="locationVisible" width="800px" append-to-body class="map-dialog"> | ||
| 108 | + <div class="map-container-wrapper"> | ||
| 109 | + <div class="map-header-bar"> | ||
| 110 | + <span>在地图上点击以选择门店位置(仅支持单个标记)</span> | ||
| 111 | + <div class="coordinate-info" v-if="tempMarker.lng"> | ||
| 112 | + 当前选择:{{ tempMarker.lng.toFixed(6) }}, {{ tempMarker.lat.toFixed(6) }} | ||
| 113 | + </div> | ||
| 114 | + </div> | ||
| 115 | + <div id="location-map" class="map-canvas"></div> | ||
| 116 | + </div> | ||
| 117 | + <span slot="footer" class="dialog-footer"> | ||
| 118 | + <el-button @click="locationVisible = false">取 消</el-button> | ||
| 119 | + <el-button type="primary" @click="confirmLocation" :disabled="!tempMarker.lng">确 定</el-button> | ||
| 120 | + </span> | ||
| 121 | + </el-dialog> | ||
| 122 | + | ||
| 123 | + <!-- 围栏设置弹窗 --> | ||
| 124 | + <el-dialog title="设置电子围栏" :visible.sync="fenceVisible" width="1000px" append-to-body class="map-dialog"> | ||
| 125 | + <div class="fence-editor-layout"> | ||
| 126 | + <div class="map-side-panel"> | ||
| 127 | + <div class="panel-header">图形管理 ({{ fenceBuffer.length }})</div> | ||
| 128 | + <div class="shape-list"> | ||
| 129 | + <div v-for="(shape, index) in fenceBuffer" :key="index" class="shape-item"> | ||
| 130 | + <i :class="getShapeIcon(shape.type)"></i> | ||
| 131 | + <span class="shape-name">{{ getShapeName(shape.type) }} {{ index + 1 }}</span> | ||
| 132 | + <el-button type="text" icon="el-icon-delete" class="delete-btn" | ||
| 133 | + @click="removeBufferShape(index)"></el-button> | ||
| 134 | + </div> | ||
| 135 | + <div v-if="!fenceBuffer.length" class="empty-text">暂无图形,请在右侧绘制</div> | ||
| 136 | + </div> | ||
| 137 | + <div class="panel-footer"> | ||
| 138 | + <p class="warning-text" v-if="fenceBuffer.length > 1"> | ||
| 139 | + <i class="el-icon-warning"></i> 注意:最终只能保留1个围栏 | ||
| 140 | + </p> | ||
| 141 | + </div> | ||
| 142 | + </div> | ||
| 143 | + <div class="map-main-area"> | ||
| 144 | + <div class="map-toolbar"> | ||
| 145 | + <div v-for="tool in fenceTools" :key="tool.id" class="tool-btn" | ||
| 146 | + :class="{ active: activeFenceTool === tool.id }" @click="changeFenceTool(tool.id)"> | ||
| 147 | + <span class="tool-icon" :class="'tool-icon--' + tool.id"></span> | ||
| 148 | + <span class="tool-label">{{ tool.name }}</span> | ||
| 149 | + </div> | ||
| 150 | + </div> | ||
| 151 | + <div id="fence-map" class="map-canvas"></div> | ||
| 152 | + </div> | ||
| 153 | + </div> | ||
| 154 | + <span slot="footer" class="dialog-footer"> | ||
| 155 | + <div class="footer-hint" v-if="fenceBuffer.length > 1">请删除多余图形,仅保留一个围栏后再保存</div> | ||
| 156 | + <el-button @click="fenceVisible = false">取 消</el-button> | ||
| 157 | + <el-button type="primary" @click="confirmFence" :disabled="fenceBuffer.length !== 1">确 定 保 存</el-button> | ||
| 158 | + </span> | ||
| 159 | + </el-dialog> | ||
| 122 | </el-dialog> | 160 | </el-dialog> |
| 123 | </template> | 161 | </template> |
| 162 | + | ||
| 124 | <script> | 163 | <script> |
| 125 | - import request from '@/utils/request' | ||
| 126 | - import { getDictionaryDataSelector } from '@/api/systemData/dictionary' | ||
| 127 | - import { previewDataInterface } from '@/api/systemData/dataInterface' | ||
| 128 | - export default { | ||
| 129 | - components: {}, | ||
| 130 | - props: [], | ||
| 131 | - data() { | ||
| 132 | - return { | ||
| 133 | - loading: false, | ||
| 134 | - visible: false, | ||
| 135 | - isDetail: false, | ||
| 136 | - dataForm: { | ||
| 137 | - id:'', | ||
| 138 | - id:undefined, | ||
| 139 | - mdbm:undefined, | ||
| 140 | - djmdbh:undefined, | ||
| 141 | - djmd:undefined, | ||
| 142 | - dm:undefined, | ||
| 143 | - cs:undefined, | ||
| 144 | - dz:undefined, | ||
| 145 | - xm:undefined, | ||
| 146 | - dhhm:undefined, | ||
| 147 | - zj:undefined, | ||
| 148 | - kysj:undefined, | ||
| 149 | - zxzt:undefined, | ||
| 150 | - gsmc:undefined, | ||
| 151 | - fr:undefined, | ||
| 152 | - ywsb:undefined, | ||
| 153 | - zzrs:0, | ||
| 154 | - storeCategory:undefined, | ||
| 155 | - storeType:undefined, | ||
| 156 | - }, | ||
| 157 | - rules: { | ||
| 158 | - }, | ||
| 159 | - zxztOptions:[{"fullName":"开店","id":"开店"},{"fullName":"闭店","id":"闭店"}], | ||
| 160 | - ywsbOptions:[{"fullName":"有","id":"有"},{"fullName":"无","id":"无"}], | ||
| 161 | - storeCategoryOptions:[], | ||
| 162 | - storeTypeOptions:[], | ||
| 163 | - } | 164 | +import request from '@/utils/request' |
| 165 | + | ||
| 166 | +export default { | ||
| 167 | + data() { | ||
| 168 | + return { | ||
| 169 | + loading: false, | ||
| 170 | + visible: false, | ||
| 171 | + isDetail: false, | ||
| 172 | + dataForm: { | ||
| 173 | + id: undefined, | ||
| 174 | + mdbm: undefined, | ||
| 175 | + dm: undefined, | ||
| 176 | + dz: undefined, | ||
| 177 | + cs: undefined, | ||
| 178 | + xm: undefined, | ||
| 179 | + dhhm: undefined, | ||
| 180 | + zxzt: undefined, | ||
| 181 | + storeCategory: undefined, | ||
| 182 | + storeType: undefined, | ||
| 183 | + longitude: null, | ||
| 184 | + latitude: null, | ||
| 185 | + fencePolygons: [], | ||
| 186 | + }, | ||
| 187 | + rules: { | ||
| 188 | + mdbm: [{ required: true, message: '请输入门店编码', trigger: 'blur' }], | ||
| 189 | + dm: [{ required: true, message: '请输入店名', trigger: 'blur' }], | ||
| 190 | + dz: [{ required: true, message: '请输入地址', trigger: 'blur' }], | ||
| 191 | + }, | ||
| 192 | + zxztOptions: [{ fullName: '开店', id: '开店' }, { fullName: '闭店', id: '闭店' }], | ||
| 193 | + storeCategoryOptions: [], | ||
| 194 | + storeTypeOptions: [], | ||
| 195 | + | ||
| 196 | + // 定位弹窗相关 | ||
| 197 | + locationVisible: false, | ||
| 198 | + locationMap: null, | ||
| 199 | + locationMarkerLayer: null, | ||
| 200 | + tempMarker: { lng: null, lat: null }, | ||
| 201 | + | ||
| 202 | + // 围栏弹窗相关 | ||
| 203 | + fenceVisible: false, | ||
| 204 | + fenceMap: null, | ||
| 205 | + fenceEditor: null, | ||
| 206 | + fenceDrawLayers: {}, // 绘图图层(只保留多边形 / 圆形) | ||
| 207 | + fenceDisplayLayer: null, // 展示层(显示 buffer 中的图形) | ||
| 208 | + activeFenceTool: 'polygon', | ||
| 209 | + fenceBuffer: [], // 临时存放绘制的多个图形:[{ id, type, points, geometry }] | ||
| 210 | + // 目前仅支持多边形 / 圆形两个工具,矩形与椭圆功能取消 | ||
| 211 | + fenceTools: [ | ||
| 212 | + { id: 'polygon', name: '多边形' }, | ||
| 213 | + { id: 'circle', name: '圆形' } | ||
| 214 | + ] | ||
| 215 | + } | ||
| 216 | + }, | ||
| 217 | + created() { | ||
| 218 | + this.loadStoreCategoryOptions(); | ||
| 219 | + this.loadStoreTypeOptions(); | ||
| 220 | + }, | ||
| 221 | + methods: { | ||
| 222 | + loadStoreCategoryOptions() { | ||
| 223 | + request({ url: '/api/Extend/lqmdxx/Selector/StoreCategory', method: 'get' }) | ||
| 224 | + .then(res => { this.storeCategoryOptions = res.data || []; }); | ||
| 164 | }, | 225 | }, |
| 165 | - computed: {}, | ||
| 166 | - watch: {}, | ||
| 167 | - created() { | ||
| 168 | - this.loadStoreCategoryOptions(); | ||
| 169 | - this.loadStoreTypeOptions(); | 226 | + loadStoreTypeOptions() { |
| 227 | + request({ url: '/api/Extend/lqmdxx/Selector/StoreType', method: 'get' }) | ||
| 228 | + .then(res => { this.storeTypeOptions = res.data || []; }); | ||
| 170 | }, | 229 | }, |
| 171 | - mounted() { | ||
| 172 | - }, | ||
| 173 | - methods: { | ||
| 174 | - goBack() { | ||
| 175 | - this.$emit('refresh') | ||
| 176 | - }, | ||
| 177 | - // 加载门店类别选项 | ||
| 178 | - loadStoreCategoryOptions() { | ||
| 179 | - request({ | ||
| 180 | - url: '/api/Extend/lqmdxx/Selector/StoreCategory', | ||
| 181 | - method: 'get' | ||
| 182 | - }).then(res => { | ||
| 183 | - this.storeCategoryOptions = res.data || []; | ||
| 184 | - }).catch(err => { | ||
| 185 | - console.error('加载门店类别选项失败:', err); | ||
| 186 | - this.storeCategoryOptions = []; | 230 | + |
| 231 | + init(id, isDetail) { | ||
| 232 | + this.dataForm.id = id || 0; | ||
| 233 | + this.visible = true; | ||
| 234 | + this.isDetail = isDetail || false; | ||
| 235 | + this.$nextTick(() => { | ||
| 236 | + this.$refs['elForm'].resetFields(); | ||
| 237 | + if (this.dataForm.id) { | ||
| 238 | + request({ url: '/api/Extend/LqMdxx/' + this.dataForm.id, method: 'get' }) | ||
| 239 | + .then(res => { | ||
| 240 | + this.dataForm = res.data; | ||
| 241 | + }); | ||
| 242 | + } | ||
| 243 | + }) | ||
| 244 | + }, | ||
| 245 | + | ||
| 246 | + loadTMapScript() { | ||
| 247 | + return new Promise((resolve, reject) => { | ||
| 248 | + if (window.TMap) return resolve(); | ||
| 249 | + const script = document.createElement('script'); | ||
| 250 | + script.src = 'https://map.qq.com/api/gljs?v=1.exp&key=YRXBZ-NEV6T-K7SXH-VJPMF-G5IQF-F3FCJ&libraries=tools,geometry'; | ||
| 251 | + script.onload = resolve; | ||
| 252 | + script.onerror = reject; | ||
| 253 | + document.body.appendChild(script); | ||
| 254 | + }); | ||
| 255 | + }, | ||
| 256 | + | ||
| 257 | + // --- 门店定位逻辑 --- | ||
| 258 | + handleOpenLocation() { | ||
| 259 | + this.locationVisible = true; | ||
| 260 | + this.tempMarker = { lng: this.dataForm.longitude, lat: this.dataForm.latitude }; | ||
| 261 | + this.$nextTick(() => { | ||
| 262 | + this.initLocationMap(); | ||
| 263 | + }); | ||
| 264 | + }, | ||
| 265 | + | ||
| 266 | + initLocationMap() { | ||
| 267 | + this.loadTMapScript().then(() => { | ||
| 268 | + const TMap = window.TMap; | ||
| 269 | + const centerLat = this.tempMarker.lat || 30.656149; // 成都 | ||
| 270 | + const centerLng = this.tempMarker.lng || 104.065735; | ||
| 271 | + const center = new TMap.LatLng(centerLat, centerLng); | ||
| 272 | + | ||
| 273 | + this.locationMap = new TMap.Map('location-map', { center, zoom: 14 }); | ||
| 274 | + this.locationMarkerLayer = new TMap.MultiMarker({ map: this.locationMap, geometries: [] }); | ||
| 275 | + | ||
| 276 | + if (this.tempMarker.lng) { | ||
| 277 | + this.locationMarkerLayer.setGeometries([{ id: 'm', position: new TMap.LatLng(this.tempMarker.lat, this.tempMarker.lng) }]); | ||
| 278 | + } | ||
| 279 | + | ||
| 280 | + this.locationMap.on('click', (evt) => { | ||
| 281 | + if (!evt.latLng) return; | ||
| 282 | + const lat = evt.latLng.getLat(); | ||
| 283 | + const lng = evt.latLng.getLng(); | ||
| 284 | + this.tempMarker = { lng, lat }; | ||
| 285 | + this.locationMarkerLayer.setGeometries([{ id: 'm', position: evt.latLng }]); | ||
| 187 | }); | 286 | }); |
| 188 | - }, | ||
| 189 | - // 加载门店类型选项 | ||
| 190 | - loadStoreTypeOptions() { | ||
| 191 | - request({ | ||
| 192 | - url: '/api/Extend/lqmdxx/Selector/StoreType', | ||
| 193 | - method: 'get' | ||
| 194 | - }).then(res => { | ||
| 195 | - this.storeTypeOptions = res.data || []; | ||
| 196 | - }).catch(err => { | ||
| 197 | - console.error('加载门店类型选项失败:', err); | ||
| 198 | - this.storeTypeOptions = []; | 287 | + }); |
| 288 | + }, | ||
| 289 | + | ||
| 290 | + confirmLocation() { | ||
| 291 | + this.dataForm.longitude = this.tempMarker.lng; | ||
| 292 | + this.dataForm.latitude = this.tempMarker.lat; | ||
| 293 | + this.locationVisible = false; | ||
| 294 | + }, | ||
| 295 | + | ||
| 296 | + // --- 围栏设置逻辑 --- | ||
| 297 | + handleOpenFence() { | ||
| 298 | + if (!this.dataForm.longitude) return; | ||
| 299 | + this.fenceVisible = true; | ||
| 300 | + // 初始化 Buffer:历史上如果有多块,只保留第一块,保证始终至多一个围栏 | ||
| 301 | + const polygons = Array.isArray(this.dataForm.fencePolygons) ? this.dataForm.fencePolygons : []; | ||
| 302 | + if (polygons.length > 0 && Array.isArray(polygons[0])) { | ||
| 303 | + this.fenceBuffer = [{ | ||
| 304 | + id: `old-${Date.now()}`, | ||
| 305 | + type: 'polygon', | ||
| 306 | + points: polygons[0] | ||
| 307 | + }]; | ||
| 308 | + } else { | ||
| 309 | + this.fenceBuffer = []; | ||
| 310 | + } | ||
| 311 | + this.$nextTick(() => { | ||
| 312 | + this.initFenceMap(); | ||
| 313 | + }); | ||
| 314 | + }, | ||
| 315 | + | ||
| 316 | + initFenceMap() { | ||
| 317 | + this.loadTMapScript().then(() => { | ||
| 318 | + const TMap = window.TMap; | ||
| 319 | + const center = new TMap.LatLng(this.dataForm.latitude, this.dataForm.longitude); | ||
| 320 | + this.fenceMap = new TMap.Map('fence-map', { center, zoom: 16 }); | ||
| 321 | + | ||
| 322 | + // 1. 门店位置固定标点 | ||
| 323 | + this.fenceStoreMarkerLayer = new TMap.MultiMarker({ | ||
| 324 | + map: this.fenceMap, | ||
| 325 | + geometries: [{ id: 'store', position: center }] | ||
| 199 | }); | 326 | }); |
| 200 | - }, | ||
| 201 | - init(id, isDetail) { | ||
| 202 | - this.dataForm.id = id || 0; | ||
| 203 | - this.visible = true; | ||
| 204 | - this.isDetail = isDetail || false; | ||
| 205 | - this.$nextTick(() => { | ||
| 206 | - this.$refs['elForm'].resetFields(); | ||
| 207 | - if (this.dataForm.id) { | ||
| 208 | - request({ | ||
| 209 | - url: '/api/Extend/LqMdxx/' + this.dataForm.id, | ||
| 210 | - method: 'get' | ||
| 211 | - }).then(res =>{ | ||
| 212 | - this.dataForm = res.data; | 327 | + |
| 328 | + // 2. 初始化展示层 | ||
| 329 | + this.fenceDisplayLayer = new TMap.MultiPolygon({ | ||
| 330 | + map: this.fenceMap, | ||
| 331 | + geometries: [], | ||
| 332 | + styles: { | ||
| 333 | + default: new TMap.PolygonStyle({ | ||
| 334 | + color: 'rgba(41,182,246,0.2)', | ||
| 335 | + borderColor: 'rgba(41,182,246,0.9)', | ||
| 336 | + borderWidth: 2 | ||
| 213 | }) | 337 | }) |
| 214 | } | 338 | } |
| 339 | + }); | ||
| 340 | + | ||
| 341 | + // 3. 构建临时绘制图层: | ||
| 342 | + // - 一个多边形图层 polygonLayer | ||
| 343 | + // - 一个圆形图层 circleLayer | ||
| 344 | + const polygonLayer = new TMap.MultiPolygon({ | ||
| 345 | + map: this.fenceMap, | ||
| 346 | + geometries: [], | ||
| 347 | + styles: { | ||
| 348 | + default: new TMap.PolygonStyle({ | ||
| 349 | + color: 'rgba(255,152,0,0.2)', | ||
| 350 | + borderColor: '#FF9800', | ||
| 351 | + borderWidth: 2 | ||
| 352 | + }) | ||
| 353 | + } | ||
| 354 | + }); | ||
| 355 | + const circleLayer = new TMap.MultiCircle({ | ||
| 356 | + map: this.fenceMap, | ||
| 357 | + geometries: [], | ||
| 358 | + styles: { | ||
| 359 | + default: new TMap.CircleStyle({ | ||
| 360 | + color: 'rgba(255,152,0,0.2)', | ||
| 361 | + borderColor: '#FF9800', | ||
| 362 | + borderWidth: 2 | ||
| 363 | + }) | ||
| 364 | + } | ||
| 365 | + }); | ||
| 366 | + this.fenceDrawLayers = { | ||
| 367 | + polygon: polygonLayer, | ||
| 368 | + circle: circleLayer | ||
| 369 | + }; | ||
| 370 | + | ||
| 371 | + // 4. 初始化唯一编辑器(后续不再整体销毁,只清空内容) | ||
| 372 | + this.fenceEditor = new TMap.tools.GeometryEditor({ | ||
| 373 | + map: this.fenceMap, | ||
| 374 | + overlayList: [ | ||
| 375 | + { overlay: polygonLayer, id: 'polygon' }, | ||
| 376 | + { overlay: circleLayer, id: 'circle' } | ||
| 377 | + ], | ||
| 378 | + actionMode: TMap.tools.constants.EDITOR_ACTION.DRAW, | ||
| 379 | + activeOverlayId: 'polygon', | ||
| 380 | + snappable: true | ||
| 381 | + }); | ||
| 382 | + | ||
| 383 | + // 5. 监听绘制完毕事件:每次只保留当前绘制结果为唯一围栏 | ||
| 384 | + this.fenceEditor.on('draw_complete', (geometry) => { | ||
| 385 | + const toolId = this.activeFenceTool; | ||
| 386 | + const points = this._extractPoints(toolId, geometry); | ||
| 387 | + | ||
| 388 | + if (points && points.length >= 3) { | ||
| 389 | + // 业务约束:无论之前画了什么,本次绘制即为“唯一围栏” | ||
| 390 | + this.fenceBuffer = [{ | ||
| 391 | + id: `shape-${Date.now()}`, | ||
| 392 | + type: toolId, | ||
| 393 | + points: points | ||
| 394 | + }]; | ||
| 395 | + this.refreshFenceDisplay(); | ||
| 396 | + } | ||
| 397 | + | ||
| 398 | + // 绘制完毕后:不销毁 Editor,只清空对应图层的临时几何 | ||
| 399 | + const drawLayer = this.fenceDrawLayers[toolId]; | ||
| 400 | + if (drawLayer && typeof drawLayer.setGeometries === 'function') { | ||
| 401 | + drawLayer.setGeometries([]); | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + // 延迟一帧重置绘制状态,避免与内部事件冲突 | ||
| 405 | + setTimeout(() => { | ||
| 406 | + if (this.fenceEditor && window.TMap && window.TMap.tools && window.TMap.tools.constants) { | ||
| 407 | + this.fenceEditor.setActiveOverlay(toolId); | ||
| 408 | + this.fenceEditor.setActionMode(window.TMap.tools.constants.EDITOR_ACTION.DRAW); | ||
| 409 | + } | ||
| 410 | + }, 20); | ||
| 411 | + }); | ||
| 412 | + | ||
| 413 | + this.refreshFenceDisplay(); | ||
| 414 | + }); | ||
| 415 | + }, | ||
| 416 | + | ||
| 417 | + changeFenceTool(id) { | ||
| 418 | + this.activeFenceTool = id; | ||
| 419 | + if (this.fenceEditor) { | ||
| 420 | + // 清除可能画了一半的所有绘制层(去重后防止同一图层重复清理) | ||
| 421 | + const uniqueLayers = Object.values(this.fenceDrawLayers).filter((layer, index, arr) => arr.indexOf(layer) === index); | ||
| 422 | + uniqueLayers.forEach(layer => { | ||
| 423 | + if (layer && typeof layer.setGeometries === 'function') { | ||
| 424 | + layer.setGeometries([]); | ||
| 425 | + } | ||
| 426 | + }); | ||
| 427 | + | ||
| 428 | + this.fenceEditor.setActiveOverlay(id); | ||
| 429 | + this.fenceEditor.setActionMode(window.TMap.tools.constants.EDITOR_ACTION.DRAW); | ||
| 430 | + } | ||
| 431 | + }, | ||
| 432 | + | ||
| 433 | + refreshFenceDisplay() { | ||
| 434 | + if (!this.fenceDisplayLayer) return; | ||
| 435 | + const TMap = window.TMap; | ||
| 436 | + const geometries = this.fenceBuffer.map(item => { | ||
| 437 | + const path = item.points.map(p => new TMap.LatLng(p.lat, p.lng)); | ||
| 438 | + // 闭合 | ||
| 439 | + if (path[0].getLat() !== path[path.length - 1].getLat() || path[0].getLng() !== path[path.length - 1].getLng()) { | ||
| 440 | + path.push(path[0]); | ||
| 441 | + } | ||
| 442 | + return { id: item.id, paths: [path] }; | ||
| 443 | + }); | ||
| 444 | + this.fenceDisplayLayer.setGeometries(geometries); | ||
| 445 | + }, | ||
| 446 | + | ||
| 447 | + removeBufferShape(index) { | ||
| 448 | + this.fenceBuffer.splice(index, 1); | ||
| 449 | + this.refreshFenceDisplay(); | ||
| 450 | + }, | ||
| 451 | + | ||
| 452 | + confirmFence() { | ||
| 453 | + if (this.fenceBuffer.length !== 1) { | ||
| 454 | + this.$message.warning('请确保最终只保留一个围栏'); | ||
| 455 | + return; | ||
| 456 | + } | ||
| 457 | + this.dataForm.fencePolygons = [this.fenceBuffer[0].points]; | ||
| 458 | + this.fenceVisible = false; | ||
| 459 | + }, | ||
| 460 | + | ||
| 461 | + // 将 GeometryEditor 返回的几何统一转换为点数组 | ||
| 462 | + _extractPoints(toolId, geometry) { | ||
| 463 | + if (!geometry) return [] | ||
| 464 | + | ||
| 465 | + // 通用:从 geometry 中尝试解析点数组(paths 或 path,一维或二维) | ||
| 466 | + let pointsArray = [] | ||
| 467 | + if (Array.isArray(geometry.paths) && geometry.paths.length) { | ||
| 468 | + const first = geometry.paths[0] | ||
| 469 | + pointsArray = Array.isArray(first) ? first : geometry.paths | ||
| 470 | + } else if (Array.isArray(geometry.path) && geometry.path.length) { | ||
| 471 | + const first = geometry.path[0] | ||
| 472 | + pointsArray = Array.isArray(first) ? first : geometry.path | ||
| 473 | + } | ||
| 474 | + | ||
| 475 | + // 多边形 / 矩形 / 椭圆:统一按点数组处理 | ||
| 476 | + if (['polygon', 'rectangle', 'ellipse'].includes(toolId)) { | ||
| 477 | + if (!Array.isArray(pointsArray) || !pointsArray.length) return [] | ||
| 478 | + return pointsArray.map(p => ({ | ||
| 479 | + lng: typeof p.getLng === 'function' ? p.getLng() : p.lng, | ||
| 480 | + lat: typeof p.getLat === 'function' ? p.getLat() : p.lat | ||
| 481 | + })) | ||
| 482 | + } | ||
| 483 | + | ||
| 484 | + // 圆形:用中心 + 半径近似成 36 边多边形 | ||
| 485 | + if (toolId === 'circle' && geometry.center && geometry.radius) { | ||
| 486 | + const center = geometry.center | ||
| 487 | + const r = geometry.radius | ||
| 488 | + const cLat = typeof center.getLat === 'function' ? center.getLat() : center.lat | ||
| 489 | + const cLng = typeof center.getLng === 'function' ? center.getLng() : center.lng | ||
| 490 | + const R = 6378137 | ||
| 491 | + const latRad = (cLat * Math.PI) / 180 | ||
| 492 | + return Array.from({ length: 36 }, (_, i) => { | ||
| 493 | + const angle = (2 * Math.PI * i) / 36 | ||
| 494 | + return { | ||
| 495 | + lat: cLat + (r * Math.cos(angle)) / R * (180 / Math.PI), | ||
| 496 | + lng: cLng + (r * Math.sin(angle)) / (R * Math.cos(latRad)) * (180 / Math.PI) | ||
| 497 | + } | ||
| 215 | }) | 498 | }) |
| 216 | - }, | ||
| 217 | - dataFormSubmit() { | ||
| 218 | - this.$refs['elForm'].validate((valid) => { | ||
| 219 | - if (valid) { | ||
| 220 | - if (!this.dataForm.id) { | ||
| 221 | - request({ | ||
| 222 | - url: `/api/Extend/LqMdxx`, | ||
| 223 | - method: 'post', | ||
| 224 | - data: this.dataForm, | ||
| 225 | - }).then((res) => { | ||
| 226 | - this.$message({ | ||
| 227 | - message: res.msg, | ||
| 228 | - type: 'success', | ||
| 229 | - duration: 1000, | ||
| 230 | - onClose: () => { | ||
| 231 | - this.visible = false, | ||
| 232 | - this.$emit('refresh', true) | ||
| 233 | - } | ||
| 234 | - }) | ||
| 235 | - }) | ||
| 236 | - } else { | ||
| 237 | - request({ | ||
| 238 | - url: '/api/Extend/LqMdxx/' + this.dataForm.id, | ||
| 239 | - method: 'PUT', | ||
| 240 | - data: this.dataForm | ||
| 241 | - }).then((res) => { | ||
| 242 | - this.$message({ | ||
| 243 | - message: res.msg, | ||
| 244 | - type: 'success', | ||
| 245 | - duration: 1000, | ||
| 246 | - onClose: () => { | ||
| 247 | - this.visible = false | ||
| 248 | - this.$emit('refresh', true) | ||
| 249 | - } | ||
| 250 | - }) | ||
| 251 | - }) | ||
| 252 | - } | ||
| 253 | - } | ||
| 254 | - }) | ||
| 255 | - }, | 499 | + } |
| 500 | + | ||
| 501 | + return [] | ||
| 502 | + }, | ||
| 503 | + | ||
| 504 | + getShapeIcon(type) { | ||
| 505 | + const icons = { polygon: 'el-icon-picture', circle: 'el-icon-loading', rectangle: 'el-icon-full-screen', ellipse: 'el-icon-help' }; | ||
| 506 | + return icons[type] || 'el-icon-info'; | ||
| 507 | + }, | ||
| 508 | + | ||
| 509 | + getShapeName(type) { | ||
| 510 | + const names = { polygon: '多边形', circle: '圆形', rectangle: '矩形', ellipse: '椭圆' }; | ||
| 511 | + return names[type] || '图形'; | ||
| 512 | + }, | ||
| 513 | + | ||
| 514 | + dataFormSubmit() { | ||
| 515 | + this.$refs['elForm'].validate((valid) => { | ||
| 516 | + if (!valid) return; | ||
| 517 | + const isNew = !this.dataForm.id; | ||
| 518 | + request({ | ||
| 519 | + url: isNew ? '/api/Extend/LqMdxx' : `/api/Extend/LqMdxx/${this.dataForm.id}`, | ||
| 520 | + method: isNew ? 'POST' : 'PUT', | ||
| 521 | + data: this.dataForm | ||
| 522 | + }).then((res) => { | ||
| 523 | + this.$message({ | ||
| 524 | + message: res.msg, | ||
| 525 | + type: 'success', | ||
| 526 | + duration: 1000, | ||
| 527 | + onClose: () => { | ||
| 528 | + this.visible = false; | ||
| 529 | + this.$emit('refresh', true); | ||
| 530 | + } | ||
| 531 | + }) | ||
| 532 | + }) | ||
| 533 | + }) | ||
| 256 | } | 534 | } |
| 257 | } | 535 | } |
| 536 | +} | ||
| 258 | </script> | 537 | </script> |
| 538 | + | ||
| 539 | +<style lang="scss" scoped> | ||
| 540 | +.fence-status-bar { | ||
| 541 | + display: flex; | ||
| 542 | + align-items: center; | ||
| 543 | + padding: 5px 0; | ||
| 544 | + | ||
| 545 | + .hint-text { | ||
| 546 | + font-size: 12px; | ||
| 547 | + color: #f56c6c; | ||
| 548 | + margin-left: 8px; | ||
| 549 | + } | ||
| 550 | +} | ||
| 551 | + | ||
| 552 | +.map-dialog { | ||
| 553 | + ::v-deep .el-dialog__body { | ||
| 554 | + padding: 10px 20px; | ||
| 555 | + } | ||
| 556 | +} | ||
| 557 | + | ||
| 558 | +.map-container-wrapper { | ||
| 559 | + .map-header-bar { | ||
| 560 | + display: flex; | ||
| 561 | + justify-content: space-between; | ||
| 562 | + font-size: 13px; | ||
| 563 | + color: #606266; | ||
| 564 | + margin-bottom: 8px; | ||
| 565 | + | ||
| 566 | + .coordinate-info { | ||
| 567 | + color: #409eff; | ||
| 568 | + font-weight: bold; | ||
| 569 | + } | ||
| 570 | + } | ||
| 571 | +} | ||
| 572 | + | ||
| 573 | +.map-canvas { | ||
| 574 | + width: 100%; | ||
| 575 | + height: 450px; | ||
| 576 | + border-radius: 4px; | ||
| 577 | + border: 1px solid #dcdfe6; | ||
| 578 | +} | ||
| 579 | + | ||
| 580 | +.fence-editor-layout { | ||
| 581 | + display: flex; | ||
| 582 | + height: 500px; | ||
| 583 | + gap: 15px; | ||
| 584 | + | ||
| 585 | + .map-side-panel { | ||
| 586 | + width: 220px; | ||
| 587 | + border: 1px solid #ebeef5; | ||
| 588 | + border-radius: 4px; | ||
| 589 | + display: flex; | ||
| 590 | + flex-direction: column; | ||
| 591 | + | ||
| 592 | + .panel-header { | ||
| 593 | + padding: 10px; | ||
| 594 | + background: #f5f7fa; | ||
| 595 | + border-bottom: 1px solid #ebeef5; | ||
| 596 | + font-weight: bold; | ||
| 597 | + font-size: 14px; | ||
| 598 | + } | ||
| 599 | + | ||
| 600 | + .shape-list { | ||
| 601 | + flex: 1; | ||
| 602 | + overflow-y: auto; | ||
| 603 | + padding: 10px; | ||
| 604 | + | ||
| 605 | + .shape-item { | ||
| 606 | + display: flex; | ||
| 607 | + align-items: center; | ||
| 608 | + padding: 8px; | ||
| 609 | + margin-bottom: 8px; | ||
| 610 | + background: #fdfdfd; | ||
| 611 | + border: 1px solid #f2f2f2; | ||
| 612 | + border-radius: 4px; | ||
| 613 | + | ||
| 614 | + i { | ||
| 615 | + margin-right: 8px; | ||
| 616 | + color: #409eff; | ||
| 617 | + } | ||
| 618 | + | ||
| 619 | + .shape-name { | ||
| 620 | + flex: 1; | ||
| 621 | + font-size: 12px; | ||
| 622 | + } | ||
| 623 | + | ||
| 624 | + .delete-btn { | ||
| 625 | + color: #f56c6c; | ||
| 626 | + padding: 0; | ||
| 627 | + } | ||
| 628 | + } | ||
| 629 | + | ||
| 630 | + .empty-text { | ||
| 631 | + text-align: center; | ||
| 632 | + color: #909399; | ||
| 633 | + font-size: 12px; | ||
| 634 | + margin-top: 50px; | ||
| 635 | + } | ||
| 636 | + } | ||
| 637 | + | ||
| 638 | + .panel-footer { | ||
| 639 | + padding: 10px; | ||
| 640 | + border-top: 1px solid #ebeef5; | ||
| 641 | + | ||
| 642 | + .warning-text { | ||
| 643 | + font-size: 11px; | ||
| 644 | + color: #e6a23c; | ||
| 645 | + margin: 0; | ||
| 646 | + } | ||
| 647 | + } | ||
| 648 | + } | ||
| 649 | + | ||
| 650 | + .map-main-area { | ||
| 651 | + flex: 1; | ||
| 652 | + display: flex; | ||
| 653 | + flex-direction: column; | ||
| 654 | + | ||
| 655 | + .map-toolbar { | ||
| 656 | + display: flex; | ||
| 657 | + padding: 0 0 10px 0; | ||
| 658 | + gap: 8px; | ||
| 659 | + | ||
| 660 | + .tool-btn { | ||
| 661 | + display: flex; | ||
| 662 | + align-items: center; | ||
| 663 | + padding: 5px 12px; | ||
| 664 | + border: 1px solid #dcdfe6; | ||
| 665 | + border-radius: 4px; | ||
| 666 | + cursor: pointer; | ||
| 667 | + background: #fff; | ||
| 668 | + transition: all 0.2s; | ||
| 669 | + | ||
| 670 | + &:hover { | ||
| 671 | + border-color: #409eff; | ||
| 672 | + color: #409eff; | ||
| 673 | + } | ||
| 674 | + | ||
| 675 | + &.active { | ||
| 676 | + background: #ecf5ff; | ||
| 677 | + border-color: #409eff; | ||
| 678 | + color: #409eff; | ||
| 679 | + } | ||
| 680 | + | ||
| 681 | + .tool-icon { | ||
| 682 | + width: 16px; | ||
| 683 | + height: 16px; | ||
| 684 | + margin-right: 6px; | ||
| 685 | + background-size: cover; | ||
| 686 | + } | ||
| 687 | + | ||
| 688 | + .tool-label { | ||
| 689 | + font-size: 12px; | ||
| 690 | + } | ||
| 691 | + } | ||
| 692 | + | ||
| 693 | + .tool-icon--polygon { | ||
| 694 | + background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/polygon.png'); | ||
| 695 | + } | ||
| 696 | + | ||
| 697 | + .tool-icon--circle { | ||
| 698 | + background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/circle.png'); | ||
| 699 | + } | ||
| 700 | + | ||
| 701 | + .tool-icon--rectangle { | ||
| 702 | + background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/rectangle.png'); | ||
| 703 | + } | ||
| 704 | + | ||
| 705 | + .tool-icon--ellipse { | ||
| 706 | + background-image: url('https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/ellipse.png'); | ||
| 707 | + } | ||
| 708 | + } | ||
| 709 | + } | ||
| 710 | +} | ||
| 711 | + | ||
| 712 | +.footer-hint { | ||
| 713 | + color: #f56c6c; | ||
| 714 | + font-size: 12px; | ||
| 715 | + margin-right: 20px; | ||
| 716 | + display: inline-block; | ||
| 717 | +} | ||
| 718 | +</style> | ||
| 259 | \ No newline at end of file | 719 | \ No newline at end of file |