文件
mashangyoujiu/Application/Retail/View/Xcx/manager·1.html

2104 行
80 KiB
HTML
可执行文件

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<!--[1.8.50] 门店管理 - 电子围栏版本-->
<script charset="utf-8" type="text/javascript" src="https://map.qq.com/api/gljs?v=1.exp&key=BHHBZ-CVK3Q-PKW5B-BJBDV-PZILV-IIBJA&libraries=service,geometry"></script>
<script>
// 全局地图加载状态
window.mapLoadStatus = {
loaded: false,
error: false
};
// 监听地图API加载
window.addEventListener('load', function() {
setTimeout(function() {
if (typeof TMap !== 'undefined') {
window.mapLoadStatus.loaded = true;
console.log('腾讯地图API加载成功');
} else {
window.mapLoadStatus.error = true;
console.error('腾讯地图API加载失败');
}
}, 1000);
});
</script>
<style type="text/css">
.tips {
font-size: 13px;
color: #999;
margin-left: 20px;
}
.el-switch__label span[aria-hidden='true'] {
color: #999;
font-weight: normal;
}
.small-input {
width: 190px;
}
.mini-input {
width: 150px;
}
.inline-block {
display: inline-block;
margin-right: 50px;
}
.time-block {
margin-top: 8px;
}
.time-block:nth-child(1) {
margin-top: 0;
}
#storeManager .el-date-editor {
width: 130px;
}
#storeManager .el-form-item--small.el-form-item {
margin-bottom: 30px;
}
#storeManager .el-input-group__append {
padding: 0 7px;
}
/* 可视化配送区域样式 */
.delivery-area-container {
border: 1px solid #e4e7ed;
border-radius: 8px;
overflow: hidden;
background: #fff;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.delivery-map-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 15px 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.delivery-map-title {
font-size: 16px;
font-weight: 600;
margin: 0;
}
.delivery-map-status {
font-size: 12px;
opacity: 0.9;
}
.delivery-map-wrapper {
position: relative;
background: #f8f9fa;
}
.delivery-map {
width: 100%;
height: 500px;
border: none;
display: block;
}
.map-toolbar {
position: absolute;
top: 15px;
left: 15px;
z-index: 1000;
display: flex;
flex-direction: column;
gap: 8px;
}
.map-tool-group {
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
padding: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
}
.map-tool-btn {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border: none;
border-radius: 6px;
background: transparent;
color: #606266;
cursor: pointer;
transition: all 0.3s ease;
font-size: 16px;
margin-bottom: 4px;
}
.map-tool-btn:last-child {
margin-bottom: 0;
}
.map-tool-btn:hover {
background: #f0f2f5;
color: #409eff;
transform: scale(1.05);
}
.map-tool-btn.active {
background: #409eff;
color: white;
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
}
.map-tool-btn.danger {
color: #f56c6c;
}
.map-tool-btn.danger:hover {
background: #fef0f0;
color: #f56c6c;
}
.drawing-tips {
position: absolute;
top: 15px;
right: 15px;
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
padding: 12px 16px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
max-width: 280px;
z-index: 1000;
}
.drawing-tips.hidden {
display: none;
}
.tips-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin: 0 0 8px 0;
display: flex;
align-items: center;
}
.tips-content {
font-size: 12px;
color: #606266;
line-height: 1.5;
margin: 0;
}
.area-management {
padding: 20px;
background: #fafbfc;
border-top: 1px solid #e4e7ed;
}
.area-list-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 15px;
}
.area-list-title {
font-size: 16px;
font-weight: 600;
color: #303133;
margin: 0;
}
.area-stats {
font-size: 12px;
color: #909399;
}
.area-list {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 15px;
max-height: 300px;
overflow-y: auto;
}
.area-item {
background: white;
border: 1px solid #e4e7ed;
border-radius: 8px;
padding: 15px;
transition: all 0.3s ease;
position: relative;
}
.area-item:hover {
border-color: #409eff;
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.15);
transform: translateY(-2px);
}
.area-item.active {
border-color: #409eff;
background: #f0f9ff;
}
.area-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.area-name {
font-size: 14px;
font-weight: 600;
color: #303133;
margin: 0;
}
.area-actions {
display: flex;
gap: 5px;
}
.area-action-btn {
width: 24px;
height: 24px;
border: none;
border-radius: 4px;
background: transparent;
color: #909399;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
}
.area-action-btn:hover {
background: #f0f2f5;
color: #409eff;
}
.area-action-btn.danger:hover {
background: #fef0f0;
color: #f56c6c;
}
.area-info {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
font-size: 12px;
color: #606266;
}
.area-info-item {
display: flex;
align-items: center;
gap: 5px;
}
.area-info-icon {
color: #909399;
}
.empty-area-list {
text-align: center;
padding: 40px 20px;
color: #909399;
}
.empty-area-icon {
font-size: 48px;
margin-bottom: 15px;
opacity: 0.5;
}
.search-controls {
position: absolute;
bottom: 15px;
left: 15px;
right: 15px;
z-index: 1000;
}
.search-input-wrapper {
display: flex;
gap: 10px;
background: rgba(255, 255, 255, 0.95);
border-radius: 8px;
padding: 10px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
backdrop-filter: blur(10px);
}
.search-input {
flex: 1;
border: 1px solid #e4e7ed;
border-radius: 6px;
padding: 8px 12px;
font-size: 14px;
outline: none;
transition: border-color 0.3s ease;
}
.search-input:focus {
border-color: #409eff;
}
.search-btn {
padding: 8px 16px;
background: #409eff;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s ease;
}
.search-btn:hover {
background: #66b1ff;
}
/* 响应式设计 */
@media (max-width: 768px) {
.delivery-map {
height: 400px;
}
.map-toolbar {
top: 10px;
left: 10px;
}
.drawing-tips {
top: 10px;
right: 10px;
max-width: 200px;
}
.area-list {
grid-template-columns: 1fr;
}
.search-controls {
bottom: 10px;
left: 10px;
right: 10px;
}
}
.fence-list {
overflow-y: auto;
border: 1px solid #e5e7eb;
border-radius: 4px;
padding: 10px;
max-height: 200px;
}
.fence-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f3f4f6;
}
.fence-item:last-child {
border-bottom: none;
}
.fence-item-info {
flex: 1;
}
.fence-item-name {
font-weight: 500;
color: #374151;
}
.fence-item-area {
font-size: 12px;
color: #6b7280;
}
.drawing-tip {
background: #fef3c7;
border: 1px solid #f59e0b;
border-radius: 4px;
padding: 8px 12px;
margin-bottom: 10px;
font-size: 13px;
color: #92400e;
}
</style>
<div id="storeManager" style="padding-bottom: 60px">
<el-collapse accordion>
<el-collapse-item>
<template slot="title">
<el-button type="text" size="mini">门店设置须知>>></el-button>
</template>
<div>1. 开启小程序商城后,才可以通过小程序进入门店</div>
<div>2. 电子围栏功能可以精确设置配送区域,支持多个不规则区域</div>
</el-collapse-item>
</el-collapse>
<el-form label-width="150px" :disabled="storeAuth.store_xcx_info==1?false:true" size="mini"
style="width: 762px" :model="ruleForm" :rules="rules" ref="ruleForm">
<el-form-item label="小程序商城" prop="status">
<el-switch v-model="ruleForm.status"
:active-text="ruleForm.status==0?'关闭':'开启'"
inactive-value="0"
active-value="1">
</el-switch>
<span class="tips">关闭则不在商城展示该门店</span>
</el-form-item>
<el-form-item label="送货上门服务" prop="skip">
<el-switch v-model="ruleForm.skip"
:active-text="ruleForm.skip==1?'关闭':'开启'"
inactive-value="1"
active-value="0">
</el-switch>
<span class="tips">关闭用户在商城下单则不可以选择同城配送</span>
</el-form-item>
<el-form-item label="默认配送时间" prop="send_delayed_time">
<el-input class="mini-input"
oninput="value=this.value.replace(/^[0]|\\D/,'')"
v-model="ruleForm.send_delayed_time" maxLength="8">
<template slot="append">分钟后</template>
</el-input>
<el-tooltip class="item" effect="dark" placement="top-start">
<div slot="content">
<p>根据下单时间往后推</p>
<p>拼团订单不会根据设置的时间设置</p>
<p>预售订单在预售产品发货期间内下单,将使用该设置</p>
</div>
<el-button icon="el-icon-question" type="text"></el-button>
</el-tooltip>
</el-form-item>
<el-form-item label="到店自提功能" prop="self_pick">
<el-switch v-model="ruleForm.self_pick"
:active-text="ruleForm.self_pick==0?'关闭':'开启'"
inactive-value="1"
active-value="0">
</el-switch>
<span class="tips">关闭用户在商城下单则不可以选择到店自提</span>
</el-form-item>
<el-form-item label="默认自提时间" prop="pickup_delayed_time">
<el-input class="mini-input"
oninput="value=this.value.replace(/^[0]|\\D/,'')"
v-model="ruleForm.pickup_delayed_time" maxLength="8">
<template slot="append">分钟后</template>
</el-input>
<el-tooltip class="item" effect="dark" placement="top-start">
<div slot="content">
<p>根据下单时间往后推</p>
<p>拼团订单不会根据设置的时间设置</p>
<p>预售订单在预售产品发货期间内下单,将使用该设置</p>
</div>
<el-button icon="el-icon-question" type="text"></el-button>
</el-tooltip>
</el-form-item>
<el-form-item label="自动生成时间" prop="auto_set_time">
<el-switch v-model="ruleForm.auto_set_time"
:active-text="ruleForm.auto_set_time==1?'开启':'关闭'"
inactive-value="0"
active-value="1">
</el-switch>
<span class="tips">开启后用户在商城下单将会按照最近时间为客户生成自提/配送时间</span>
</el-form-item>
<el-form-item label="快递发货功能" prop="express_status">
<el-switch v-model="ruleForm.express_status"
:active-text="ruleForm.express_status==1?'关闭':'开启'"
inactive-value="1"
active-value="2">
</el-switch>
<span class="tips">关闭后用户在商城下单则不可以选择快递发货</span>
</el-form-item>
<el-form-item label="非营业时间下单" prop="business_non_order">
<el-switch v-model="ruleForm.business_non_order"
:active-text="ruleForm.business_non_order==2?'关闭':'开启'"
inactive-value="2"
active-value="1">
</el-switch>
<span class="tips">关闭后不在营业时间内则商城不可以下单</span>
</el-form-item>
<el-form-item label="满额免配送费" prop="delivery_status">
<el-switch v-model="ruleForm.delivery_status"
:active-text="ruleForm.delivery_status==0?'关闭':'开启'"
inactive-value="0"
active-value="1">
</el-switch>
<span class="tips">开启后根据下面的金额设置启动免运费功能</span>
</el-form-item>
<el-form-item label="免配送费金额" prop="delivery_cost">
<el-input-number class="small-input"
:precision="2"
:step="0.01"
:max="1000000"
:min="0.00"
v-model="ruleForm.delivery_cost"></el-input-number>
<span class="tips">达到该金额以后免配送费(同城、快递)</span>
</el-form-item>
<el-form-item label="送货上门时间" prop="business">
<template v-for="(item,index) in ruleForm.business">
<div class="time-block">
<el-time-select
placeholder="开始时间"
v-model="item[0]"
value-format="HH:mm"
:picker-options="getDeliveryTime(index,1)">
</el-time-select>
<el-time-select
placeholder="结束时间"
v-model="item[1]"
value-format="HH:mm"
:picker-options="getDeliveryTime(index,2)">
</el-time-select>
<template v-if="index==0">
<el-button :disabled="ruleForm.business.length>=3?true:false"
size="mini"
@click="addBusiness()"
circle>
<i class="el-icon-plus"></i>
</el-button>
<span class="tips">送货上门服务的时间,最多可以设置3个时间段</span>
</template>
<el-button v-else
@click="spliceBusiness(index)"
size="mini"
circle>
<i class="el-icon-minus"></i>
</el-button>
</div>
</template>
</el-form-item>
<el-form-item label="营业时间" prop="business_time">
<template v-for="(item,index) in ruleForm.business_time">
<div class="time-block">
<el-time-select
placeholder="开始时间"
v-model="item[0]"
value-format="HH:mm"
:picker-options="getBusinessTime(index,1)">
</el-time-select>
<el-time-select
placeholder="结束时间"
v-model="item[1]"
value-format="HH:mm"
:picker-options="getBusinessTime(index,2)">
</el-time-select>
<template v-if="index==0">
<el-button :disabled="ruleForm.business_time.length>=3?true:false"
size="mini"
@click="addBusinessTime()"
circle>
<i class="el-icon-plus"></i>
</el-button>
<span class="tips">自提营业时间,最多可以设置3个时间段</span>
</template>
<el-button v-else
@click="spliceBusinessTime(index)"
size="mini"
circle>
<i class="el-icon-minus"></i>
</el-button>
</div>
</template>
</el-form-item>
<el-form-item label="原地址">
<el-input style="width: 500px" readonly v-model="before_address"></el-input>
</el-form-item>
<el-form-item label="经纬度" prop="longitude">
<div class="inline-block">
<span>经度</span>
<el-input class="small-input" readonly v-model="ruleForm.longitude"></el-input>
</div>
<div class="inline-block">
<span>维度</span>
<el-input class="small-input" readonly v-model="ruleForm.latitude"></el-input>
</div>
</el-form-item>
<el-form-item label="门店地址" prop="address">
<el-input style="width: 500px" v-model="ruleForm.address" placeholder="请输入门店地址"></el-input>
<el-button type="primary" size="mini" @click="searchAddress" style="margin-left: 10px;">搜索定位</el-button>
</el-form-item>
<!-- 电子围栏设置 -->
<el-form-item label="配送区域设置" prop="delivery_fences">
<div class="delivery-area-container">
<!-- 地图头部 -->
<div class="delivery-map-header">
<div>
<h3 class="delivery-map-title">
<i class="el-icon-location"></i>
可视化配送区域设置
</h3>
<div class="delivery-map-status">
<span v-if="!mapReady">地图加载中...</span>
<span v-else-if="isDrawing">绘制模式 - 点击地图添加区域边界点</span>
<span v-else>已设置 {{deliveryFences.length}} 个配送区域</span>
</div>
</div>
<div>
<el-button size="mini" type="primary" plain @click="toggleFullscreen">
<i class="el-icon-full-screen"></i>
</el-button>
</div>
</div>
<!-- 地图容器 -->
<div class="delivery-map-wrapper">
<div id="tencentMap" class="delivery-map"></div>
<!-- 地图工具栏 -->
<div class="map-toolbar">
<!-- 绘制工具组 -->
<div class="map-tool-group">
<button
class="map-tool-btn"
:class="{active: isDrawing}"
@click="toggleDrawing"
title="绘制配送区域">
<i class="el-icon-edit"></i>
</button>
<button
class="map-tool-btn"
@click="finishDrawing"
v-if="isDrawing && currentPath.length >= 3"
title="完成当前区域绘制">
<i class="el-icon-check"></i>
</button>
<button
class="map-tool-btn danger"
@click="cancelDrawing"
v-if="isDrawing"
title="取消绘制">
<i class="el-icon-close"></i>
</button>
</div>
<!-- 视图工具组 -->
<div class="map-tool-group">
<button
class="map-tool-btn"
@click="centerToStore"
title="定位到门店">
<i class="el-icon-position"></i>
</button>
<button
class="map-tool-btn"
@click="fitAllAreas"
v-if="deliveryFences.length > 0"
title="查看所有区域">
<i class="el-icon-zoom-in"></i>
</button>
</div>
<!-- 管理工具组 -->
<div class="map-tool-group" v-if="deliveryFences.length > 0">
<button
class="map-tool-btn"
@click="exportFences"
title="导出配送区域">
<i class="el-icon-download"></i>
</button>
<button
class="map-tool-btn danger"
@click="clearAllFences"
title="清空所有区域">
<i class="el-icon-delete"></i>
</button>
</div>
<!-- 导入工具 -->
<div class="map-tool-group">
<button
class="map-tool-btn"
@click="importFences"
title="导入配送区域">
<i class="el-icon-upload2"></i>
</button>
</div>
</div>
<!-- 绘制提示 -->
<div class="drawing-tips" :class="{hidden: !isDrawing}">
<h4 class="tips-title">
<i class="el-icon-info"></i>
绘制提示
</h4>
<p class="tips-content">
• 点击地图添加区域边界点<br>
• 至少需要3个点形成区域<br>
• 双击地图完成绘制<br>
• 当前已添加 {{currentPath.length}} 个点
</p>
</div>
<!-- 地址搜索 -->
<div class="search-controls">
<div class="search-input-wrapper">
<input
type="text"
class="search-input"
v-model="searchAddress"
placeholder="输入地址快速定位..."
@keyup.enter="searchLocation">
<button class="search-btn" @click="searchLocation">
<i class="el-icon-search"></i> 搜索
</button>
</div>
</div>
</div>
<!-- 区域管理面板 -->
<div class="area-management">
<div class="area-list-header">
<h4 class="area-list-title">配送区域管理</h4>
<div class="area-stats">
总计 {{deliveryFences.length}} 个区域
<span v-if="totalArea > 0">,覆盖面积约 {{totalArea.toFixed(2)}} 平方公里</span>
</div>
</div>
<!-- 区域列表 -->
<div class="area-list" v-if="deliveryFences.length > 0">
<div
v-for="(fence, index) in deliveryFences"
:key="fence.id"
class="area-item"
:class="{active: selectedAreaIndex === index}"
@click="selectArea(index)">
<div class="area-item-header">
<h5 class="area-name">{{fence.name || `配送区域 ${index + 1}`}}</h5>
<div class="area-actions">
<button
class="area-action-btn"
@click.stop="locateFence(index)"
title="定位到此区域">
<i class="el-icon-location-outline"></i>
</button>
<button
class="area-action-btn"
@click.stop="editAreaName(index)"
title="编辑区域名称">
<i class="el-icon-edit-outline"></i>
</button>
<button
class="area-action-btn danger"
@click.stop="deleteFence(index)"
title="删除此区域">
<i class="el-icon-delete"></i>
</button>
</div>
</div>
<div class="area-info">
<div class="area-info-item">
<i class="el-icon-s-grid area-info-icon"></i>
<span>面积: {{fence.area || '计算中...'}} km²</span>
</div>
<div class="area-info-item">
<i class="el-icon-connection area-info-icon"></i>
<span>边界点: {{fence.points ? fence.points.length : 0}} 个</span>
</div>
<div class="area-info-item">
<i class="el-icon-time area-info-icon"></i>
<span>创建: {{formatDate(fence.createTime)}}</span>
</div>
<div class="area-info-item">
<i class="el-icon-circle-check area-info-icon"></i>
<span>状态:
<span style="color: #67c23a;">已启用</span>
</span>
</div>
</div>
</div>
</div>
<!-- 空状态 -->
<div class="empty-area-list" v-else>
<div class="empty-area-icon">
<i class="el-icon-location-outline"></i>
</div>
<h4>暂无配送区域</h4>
<p>点击地图工具栏中的绘制按钮开始创建配送区域</p>
<el-button type="primary" size="small" @click="startDrawing">
<i class="el-icon-plus"></i> 创建第一个配送区域
</el-button>
</div>
</div>
</div>
</el-form-item>
<el-form-item label="推广语" prop="tip">
<el-input v-model="ruleForm.tip"></el-input>
<span class="tips">小程序商城门店切换页面展示</span>
</el-form-item>
<el-form-item label="门店电话" prop="phone">
<el-input class="small-input" oninput="value=this.value.replace(/^\\D|[-]{0,2}/,'')"
v-model="ruleForm.phone" maxLength="11"></el-input>
<span class="tips">小程序商城门店联系电话</span>
</el-form-item>
<el-form-item label="起送价" prop="smmoney">
<el-input class="mini-input" v-model="ruleForm.smmoney">
<template slot="append">元</template>
</el-input>
</el-form-item>
</el-form>
<div v-if="storeAuth.store_xcx_info==1" class="footer-button-box">
<el-button type="primary" @click="submitForm('ruleForm')" size="medium">立即提交</el-button>
</div>
</div>
<el-dialog title="导入配送区域JSON" :visible.sync="importDialogVisible" width="600px">
<el-input type="textarea" :rows="10" v-model="importText" placeholder="粘贴之前导出的配送区域JSON"></el-input>
<span slot="footer" class="dialog-footer">
<el-button @click="importDialogVisible=false">取 消</el-button>
<el-button type="primary" @click="confirmImport">确 定</el-button>
</span>
</el-dialog>
<script type="text/javascript" src="/Public/js/calculate.js"></script>
<script type="text/javascript">
var storeManager = new Vue({
el: "#storeManager",
data() {
return {
operate: {
delivery_fee: false,
},
before_address: "",
pageLoading: false,
// 地图相关
map: null,
marker: null,
mapReady: false, // 地图是否准备就绪
isDrawing: false,
currentPolygon: null,
currentPath: [],
drawingLine: null, // 绘制时的线条
drawingManager: null, // 原生绘制管理器
deliveryFences: [], // 配送围栏数据
polygons: [], // 地图上的多边形对象
importDialogVisible: false,
importText: '',
editIndex: null,
// 可视化功能新增属性
selectedAreaIndex: null, // 当前选中的区域索引
searchAddress: '', // 搜索地址
totalArea: 0, // 总覆盖面积
isFullscreen: false, // 是否全屏模式
ruleForm: {
id: 0,
status: "0",
skip: "1",
send_delayed_time: "0",
pickup_delayed_time: "0",
auto_set_time: "1",
self_pick: "1",
express_status: "1",
business_non_order: "2",
delivery_status: "0",
delivery_cost: '',
business: [],
business_time: [],
address: "",
longitude: 116.404,
latitude: 39.915,
tip: "",
phone: "",
smmoney: "",
delivery_fences: "", // 电子围栏数据JSON字符串
},
rules: {
delivery_cost: [{message: '请设置金额', required: false, trigger: 'change'}, {
validator: (rule, value, callback) => {
var reg = /^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d{0,2})$/;
if (storeManager.ruleForm.delivery_status == 1 && value === '' || value === undefined) {
callback(new Error("请设置金额"));
} else if (storeManager.ruleForm.delivery_status == 1 && (reg.test(value) == false || value < 0.01)) {
callback(new Error("请设置正确的金额"));
} else {
callback();
}
}, trigger: 'change'
}],
business: [{message: '请选择配送时间段', required: true, trigger: 'change'}, {
validator: (rule, value, callback) => {
if (!value || !value.length) {
callback(new Error("请选择配送时间段"));
} else {
let max = '00:00';
for (let i = 0; i < value.length; i++) {
let key = i + 1;
if (!value[i] || !value[i][0] || !value[i][1]) {
callback(new Error("请完善第" + key + "组时间段"));
return;
}
if (value[i][0] == value[i][1]) {
callback(new Error("第" + key + "组时间段开始时间不得等于结束时间"));
return;
}
if (storeManager.getTimestamp(value[i][0]) <= storeManager.getTimestamp(max) && i != 0) {
callback(new Error("第" + key + "组时间段的开始时间不得小于等于上组时间段的结束时间"));
return;
}
max = value[i][1];
}
callback();
}
}, trigger: 'change'
}],
business_time: [{message: '请选择营业时间段', required: true, trigger: 'change'}, {
validator: (rule, value, callback) => {
if (!value || !value.length) {
callback(new Error("请选择营业时间段"));
} else {
let max = '00:00';
for (let i = 0; i < value.length; i++) {
let key = i + 1;
if (!value[i] || !value[i][0] || !value[i][1]) {
callback(new Error("请完善第" + key + "组时间段"));
return;
}
if (value[i][0] == value[i][1]) {
callback(new Error("第" + key + "组时间段开始时间不得等于结束时间"));
return;
}
if (storeManager.getTimestamp(value[i][0]) <= storeManager.getTimestamp(max) && i != 0) {
callback(new Error("第" + key + "组时间段的开始时间不得小于等于上组时间段的结束时间"));
return;
}
max = value[i][1];
}
callback();
}
}, trigger: 'change'
}],
smmoney: [{message: '请设置正确的起送价', required: false, trigger: 'change'}, {
validator: (rule, value, callback) => {
var reg = /^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d{0,2})$/;
if (value && (reg.test(value) == false || value < 0)) {
callback(new Error("请设置正确的起送价"));
} else {
callback();
}
}, trigger: 'change'
}],
}
}
},
computed: {
// 计算总覆盖面积
totalArea() {
return this.deliveryFences.reduce((total, fence) => {
const area = parseFloat(fence.area) || 0;
return total + area;
}, 0);
}
},
methods: {
// 地图初始化相关方法
waitForTMapLoad() {
let attempts = 0;
const maxAttempts = 40;
const checkTMap = () => {
attempts++;
console.log(`检查地图加载状态 (${attempts}/${maxAttempts})`);
if (window.mapLoadStatus.error) {
console.error('地图API加载失败');
this.showMapError();
return;
}
if (typeof TMap !== 'undefined') {
console.log('TMap已定义,开始初始化地图');
this.initMap();
return;
}
if (attempts < maxAttempts) {
setTimeout(checkTMap, 500);
} else {
console.error('地图API加载超时');
this.showMapError();
}
};
checkTMap();
},
initMap() {
try {
const mapContainer = document.getElementById('tencentMap');
if (!mapContainer) {
this.$message.error('地图容器未找到');
return;
}
mapContainer.innerHTML = '';
const center = new TMap.LatLng(this.ruleForm.latitude, this.ruleForm.longitude);
this.map = new TMap.Map(mapContainer, {
center: center,
zoom: 13,
viewMode: '2D'
});
this.map.on('tilesloaded', () => {
this.onMapReady();
});
this.map.on('click', (evt) => {
if (this.isDrawing) {
this.addDrawingPoint(evt.latLng);
}
});
this.map.on('dblclick', (evt) => {
if (this.isDrawing && this.currentPath.length >= 3) {
this.finishDrawing();
}
});
setTimeout(() => {
if (this.map && !this.mapReady) {
this.onMapReady();
}
}, 5000);
} catch (error) {
console.error('地图初始化失败:', error);
this.showMapError();
}
},
onMapReady() {
if (this.mapReady) return;
this.mapReady = true;
this.createStoreMarker();
this.loadExistingFences();
this.$message.success('地图加载成功');
},
showMapError() {
const mapContainer = document.getElementById('tencentMap');
if (mapContainer) {
mapContainer.innerHTML = `
<div style="display: flex; align-items: center; justify-content: center; height: 100%; background: #f5f5f5; color: #666; flex-direction: column; border: 1px solid #ddd; border-radius: 4px;">
<i class="el-icon-warning" style="font-size: 48px; margin-bottom: 15px; color: #f56c6c;"></i>
<h4 style="margin: 0 0 10px 0;">地图加载失败</h4>
<p style="margin: 5px 0; font-size: 14px;">请检查网络连接或稍后重试</p>
<div style="margin-top: 15px;">
<button onclick="location.reload()" style="margin-right: 10px; padding: 8px 16px; background: #409eff; color: white; border: none; border-radius: 4px; cursor: pointer;">刷新页面</button>
<button onclick="storeManager.retryMapLoad()" style="padding: 8px 16px; background: #67c23a; color: white; border: none; border-radius: 4px; cursor: pointer;">重试加载</button>
</div>
</div>
`;
}
this.$message.error('地图加载失败,请检查网络连接');
},
retryMapLoad() {
this.mapReady = false;
this.waitForTMapLoad();
},
// 门店标记相关方法
createStoreMarker() {
try {
if (this.marker) {
this.marker.setMap(null);
this.marker = null;
}
const position = new TMap.LatLng(this.ruleForm.latitude, this.ruleForm.longitude);
if (TMap.Marker) {
this.marker = new TMap.Marker({
map: this.map,
position: position,
title: '门店位置'
});
} else if (TMap.MultiMarker) {
this.marker = new TMap.MultiMarker({
map: this.map,
styles: {
'marker': new TMap.MarkerStyle({
'width': 25,
'height': 35,
'anchor': { x: 16, y: 32 }
})
},
geometries: [{
id: 'store-marker',
styleId: 'marker',
position: position,
properties: { title: '门店位置' }
}]
});
}
} catch (error) {
console.error('创建门店标记失败:', error);
}
},
updateStoreMarker(position) {
try {
if (this.marker && this.marker.setPosition) {
this.marker.setPosition(position);
} else {
this.createStoreMarker();
}
} catch (error) {
console.error('更新门店标记失败:', error);
this.createStoreMarker();
}
},
// 地址搜索方法
searchAddress() {
if (!this.ruleForm.address) {
this.$message.warning('请输入地址');
return;
}
if (!this.map || typeof TMap === 'undefined' || !TMap.service || !TMap.service.Geocoder) {
this.$message.error('地图服务未加载');
return;
}
const geocoder = new TMap.service.Geocoder();
geocoder.getLocation({
address: this.ruleForm.address
}).then((result) => {
if (result.result && result.result.location) {
const location = result.result.location;
this.ruleForm.longitude = location.lng;
this.ruleForm.latitude = location.lat;
const newCenter = new TMap.LatLng(location.lat, location.lng);
this.map.setCenter(newCenter);
this.updateStoreMarker(newCenter);
this.$message.success('地址定位成功');
} else {
this.$message.error('地址解析失败,请检查地址是否正确');
}
}).catch((error) => {
this.$message.error('地址搜索失败');
console.error('地址搜索错误:', error);
});
},
// 可视化配送区域核心方法
toggleDrawing() {
if (this.isDrawing) {
this.cancelDrawing();
} else {
this.startDrawing();
}
},
startDrawing() {
if (!this.mapReady || !this.map) {
this.$message.error('地图未准备就绪,请稍后再试');
return;
}
if (!this.checkDrawingCapability()) {
this.$message.error('地图API不支持绘制功能,请检查网络连接后刷新页面');
return;
}
this.resetDrawingState();
this.isDrawing = true;
this.selectedAreaIndex = null;
this.$message.info('请在地图上点击多个点来绘制配送区域,至少需要3个点');
},
// 新增的可视化方法
toggleFullscreen() {
const container = document.querySelector('.delivery-area-container');
if (!document.fullscreenElement) {
container.requestFullscreen().catch(err => {
console.log('无法进入全屏模式:', err);
});
} else {
document.exitFullscreen();
}
},
centerToStore() {
if (this.map && this.ruleForm.latitude && this.ruleForm.longitude) {
const center = new TMap.LatLng(this.ruleForm.latitude, this.ruleForm.longitude);
this.map.setCenter(center);
this.map.setZoom(15);
this.$message.success('已定位到门店位置');
}
},
fitAllAreas() {
if (!this.map || this.deliveryFences.length === 0) return;
try {
let bounds = new TMap.LatLngBounds();
this.deliveryFences.forEach(fence => {
if (fence.points && fence.points.length > 0) {
fence.points.forEach(point => {
bounds.extend(new TMap.LatLng(point.lat, point.lng));
});
}
});
this.map.fitBounds(bounds, {
padding: 50
});
this.$message.success('已显示所有配送区域');
} catch (error) {
console.error('适配区域视图失败:', error);
}
},
selectArea(index) {
this.selectedAreaIndex = this.selectedAreaIndex === index ? null : index;
if (this.selectedAreaIndex !== null) {
this.locateFence(index);
}
},
locateFence(index) {
const fence = this.deliveryFences[index];
if (!fence || !fence.points || fence.points.length === 0) return;
try {
let bounds = new TMap.LatLngBounds();
fence.points.forEach(point => {
bounds.extend(new TMap.LatLng(point.lat, point.lng));
});
this.map.fitBounds(bounds, {
padding: 100
});
this.selectedAreaIndex = index;
this.$message.success(`已定位到配送区域 ${index + 1}`);
} catch (error) {
console.error('定位区域失败:', error);
}
},
editAreaName(index) {
const fence = this.deliveryFences[index];
const currentName = fence.name || `配送区域 ${index + 1}`;
this.$prompt('请输入新的区域名称', '编辑区域名称', {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputValue: currentName,
inputValidator: (value) => {
if (!value || value.trim().length === 0) {
return '区域名称不能为空';
}
if (value.length > 20) {
return '区域名称不能超过20个字符';
}
return true;
}
}).then(({ value }) => {
this.deliveryFences[index].name = value.trim();
this.updateDeliveryFencesData();
this.$message.success('区域名称已更新');
}).catch(() => {});
},
searchLocation() {
if (!this.searchAddress || !this.searchAddress.trim()) {
this.$message.warning('请输入搜索地址');
return;
}
if (!this.map || typeof TMap === 'undefined' || !TMap.service || !TMap.service.Geocoder) {
this.$message.error('地图服务未加载');
return;
}
const geocoder = new TMap.service.Geocoder();
geocoder.getLocation({
address: this.searchAddress.trim()
}).then((result) => {
if (result.result && result.result.location) {
const location = result.result.location;
const newCenter = new TMap.LatLng(location.lat, location.lng);
this.map.setCenter(newCenter);
this.map.setZoom(16);
this.$message.success('地址定位成功');
} else {
this.$message.error('未找到该地址,请检查地址是否正确');
}
}).catch((error) => {
this.$message.error('地址搜索失败');
console.error('地址搜索错误:', error);
});
},
formatDate(timestamp) {
if (!timestamp) return '未知';
const date = new Date(timestamp);
return date.toLocaleDateString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
});
},
checkDrawingCapability() {
return typeof TMap !== 'undefined' &&
(TMap.Polygon || TMap.Polyline || TMap.MultiPolygon || TMap.MultiPolyline);
},
resetDrawingState() {
this.currentPath = [];
this.editIndex = null;
this.clearCurrentDrawing();
},
clearCurrentDrawing() {
if (this.currentPolygon) {
this.currentPolygon.setMap(null);
this.currentPolygon = null;
}
if (this.drawingLine) {
this.drawingLine.setMap(null);
this.drawingLine = null;
}
},
addDrawingPoint(latLng) {
this.currentPath.push({
lat: latLng.lat,
lng: latLng.lng
});
this.updateDrawingDisplay();
if (this.currentPath.length >= 3) {
this.$message.success(`已添加第${this.currentPath.length}个点,可以完成绘制了`);
}
},
updateDrawingDisplay() {
try {
this.updateDrawingLine();
if (this.currentPath.length >= 3) {
this.updateDrawingPolygon();
}
} catch (error) {
console.error('更新绘制显示失败:', error);
}
},
updateDrawingLine() {
if (this.drawingLine) {
this.drawingLine.setMap(null);
this.drawingLine = null;
}
if (this.currentPath.length >= 2) {
const path = this.currentPath.map(p => new TMap.LatLng(p.lat, p.lng));
if (TMap.Polyline) {
this.drawingLine = new TMap.Polyline({
map: this.map,
path: path,
strokeColor: '#10b981',
strokeWeight: 3,
strokeStyle: 'solid'
});
}
}
},
updateDrawingPolygon() {
if (this.currentPolygon) {
this.currentPolygon.setMap(null);
this.currentPolygon = null;
}
const closedPath = [...this.currentPath];
const firstPoint = closedPath[0];
const lastPoint = closedPath[closedPath.length - 1];
if (firstPoint.lat !== lastPoint.lat || firstPoint.lng !== lastPoint.lng) {
closedPath.push({ lat: firstPoint.lat, lng: firstPoint.lng });
}
const latLngArray = closedPath.map(p => new TMap.LatLng(p.lat, p.lng));
if (TMap.Polygon) {
this.currentPolygon = new TMap.Polygon({
map: this.map,
paths: [latLngArray],
fillColor: 'rgba(16, 185, 129, 0.3)',
strokeColor: '#10b981',
strokeWeight: 2,
fillOpacity: 0.3
});
} else if (TMap.Polyline) {
this.currentPolygon = new TMap.Polyline({
map: this.map,
path: latLngArray,
strokeColor: '#10b981',
strokeWeight: 3
});
}
},
finishDrawing() {
if (this.currentPath.length < 3) {
this.$message.warning('至少需要3个点才能形成有效区域');
return;
}
const fenceData = this.createFenceData();
this.saveFenceData(fenceData);
this.finalizeDrawing();
},
createFenceData() {
const closedPath = [...this.currentPath];
const firstPoint = closedPath[0];
const lastPoint = closedPath[closedPath.length - 1];
if (firstPoint.lat !== lastPoint.lat || firstPoint.lng !== lastPoint.lng) {
closedPath.push({ lat: firstPoint.lat, lng: firstPoint.lng });
}
const area = this.calculatePolygonArea(closedPath);
return {
id: Date.now(),
name: `配送区域${this.deliveryFences.length + 1}`,
points: closedPath,
area: area.toFixed(2)
};
},
saveFenceData(fenceData) {
if (this.editIndex !== null) {
// 编辑模式
if (this.deliveryFences[this.editIndex]) {
fenceData.id = this.deliveryFences[this.editIndex].id || fenceData.id;
fenceData.name = this.deliveryFences[this.editIndex].name || fenceData.name;
}
this.deliveryFences.splice(this.editIndex, 1, fenceData);
if (this.polygons[this.editIndex]) {
this.polygons[this.editIndex].setMap(null);
this.polygons.splice(this.editIndex, 1, this.currentPolygon);
} else {
this.polygons[this.editIndex] = this.currentPolygon;
}
} else {
// 新增模式
this.deliveryFences.push(fenceData);
if (this.currentPolygon) {
this.polygons.push(this.currentPolygon);
}
}
},
finalizeDrawing() {
// 清除绘制线条
if (this.drawingLine) {
this.drawingLine.setMap(null);
this.drawingLine = null;
}
// 重置状态
this.isDrawing = false;
this.currentPath = [];
this.currentPolygon = null;
this.editIndex = null;
this.$message.success('配送区域绘制完成');
this.updateDeliveryFencesData();
},
cancelDrawing() {
this.clearCurrentDrawing();
this.isDrawing = false;
this.currentPath = [];
this.editIndex = null;
this.$message.info('已取消绘制');
},
// 围栏管理方法
clearAllFences() {
this.$confirm('确定要清空所有配送区域吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.polygons.forEach(polygon => polygon.setMap(null));
this.deliveryFences = [];
this.polygons = [];
this.updateDeliveryFencesData();
this.$message.success('已清空所有配送区域');
}).catch(() => {});
},
deleteFence(index) {
this.$confirm('确定要删除这个配送区域吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
if (this.polygons[index]) {
this.polygons[index].setMap(null);
this.polygons.splice(index, 1);
}
this.deliveryFences.splice(index, 1);
this.updateDeliveryFencesData();
this.$message.success('配送区域已删除');
}).catch(() => {});
},
focusFence(index) {
const fence = this.deliveryFences[index];
if (fence && fence.points.length > 0) {
const center = this.calculateFenceCenter(fence.points);
this.map.setCenter(new TMap.LatLng(center.lat, center.lng));
this.map.setZoom(15);
}
},
calculateFenceCenter(points) {
let centerLat = 0, centerLng = 0;
points.forEach(point => {
centerLat += point.lat;
centerLng += point.lng;
});
return {
lat: centerLat / points.length,
lng: centerLng / points.length
};
},
editFence(index) {
try {
const fence = this.deliveryFences[index];
if (!fence || !Array.isArray(fence.points) || fence.points.length < 3) {
this.$message.error('该区域数据无效,无法编辑');
return;
}
if (this.isDrawing) {
this.cancelDrawing();
}
this.isDrawing = true;
this.editIndex = index;
// 复制点集并移除闭合尾点
const points = fence.points.slice();
if (points.length >= 2) {
const firstPoint = points[0];
const lastPoint = points[points.length - 1];
if (firstPoint.lat === lastPoint.lat && firstPoint.lng === lastPoint.lng) {
points.pop();
}
}
this.currentPath = points.map(p => ({
lat: parseFloat(p.lat),
lng: parseFloat(p.lng)
}));
this.clearCurrentDrawing();
this.updateDrawingDisplay();
this.focusFence(index);
this.$message.info('编辑模式:在地图上点击添加新点,双击或点击"完成绘制"保存修改');
} catch (error) {
console.error('进入编辑模式失败:', error);
this.$message.error('进入编辑模式失败');
this.isDrawing = false;
this.editIndex = null;
this.currentPath = [];
}
},
// 工具方法
calculatePolygonArea(path) {
if (path.length < 3) return 0;
let area = 0;
const earthRadius = 6371;
for (let i = 0; i < path.length; i++) {
const j = (i + 1) % path.length;
const lat1 = path[i].lat * Math.PI / 180;
const lat2 = path[j].lat * Math.PI / 180;
const lng1 = path[i].lng * Math.PI / 180;
const lng2 = path[j].lng * Math.PI / 180;
area += (lng2 - lng1) * (2 + Math.sin(lat1) + Math.sin(lat2));
}
area = Math.abs(area) * earthRadius * earthRadius / 2;
return area;
},
updateDeliveryFencesData() {
this.ruleForm.delivery_fences = JSON.stringify(this.deliveryFences);
},
// 数据加载方法
loadExistingFences() {
if (!this.ruleForm.delivery_fences) {
this.deliveryFences = [];
return;
}
try {
this.clearExistingPolygons();
const fencesData = JSON.parse(this.ruleForm.delivery_fences);
if (Array.isArray(fencesData) && fencesData.length > 0) {
this.deliveryFences = fencesData;
setTimeout(() => {
this.deliveryFences.forEach((fence, index) => {
this.createFencePolygon(fence, index);
});
if (this.deliveryFences.length > 0) {
this.$message.success(`已加载${this.deliveryFences.length}个配送区域`);
}
}, 500);
} else {
this.deliveryFences = [];
}
} catch (error) {
console.error('解析围栏数据失败:', error);
this.deliveryFences = [];
this.ruleForm.delivery_fences = '';
this.$message.warning('围栏数据格式错误,已清空');
}
},
clearExistingPolygons() {
this.polygons.forEach(polygon => {
if (polygon && polygon.setMap) {
polygon.setMap(null);
}
});
this.polygons = [];
},
createFencePolygon(fence, index) {
try {
if (!fence || !fence.points || !Array.isArray(fence.points) || fence.points.length < 3) {
console.error(`围栏${index + 1}数据无效`);
return;
}
const validPoints = this.validateFencePoints(fence.points);
if (validPoints.length < 3) {
console.error(`围栏${index + 1}有效点数不足`);
return;
}
const closedPath = this.ensureClosedPath(validPoints);
const latLngArray = closedPath.map(point => new TMap.LatLng(point.lat, point.lng));
let polygon = null;
if (TMap.Polygon) {
polygon = new TMap.Polygon({
map: this.map,
paths: [latLngArray],
fillColor: 'rgba(16, 185, 129, 0.3)',
strokeColor: '#10b981',
strokeWeight: 2,
fillOpacity: 0.3
});
} else if (TMap.Polyline) {
polygon = new TMap.Polyline({
map: this.map,
path: latLngArray,
strokeColor: '#10b981',
strokeWeight: 3
});
}
if (polygon) {
this.polygons.push(polygon);
}
} catch (error) {
console.error(`创建围栏${index + 1}失败:`, error);
}
},
validateFencePoints(points) {
return points.filter(point =>
point &&
typeof point.lat === 'number' &&
typeof point.lng === 'number' &&
!isNaN(point.lat) && !isNaN(point.lng) &&
point.lat >= -90 && point.lat <= 90 &&
point.lng >= -180 && point.lng <= 180
);
},
ensureClosedPath(points) {
const path = [...points];
const firstPoint = path[0];
const lastPoint = path[path.length - 1];
if (firstPoint.lat !== lastPoint.lat || firstPoint.lng !== lastPoint.lng) {
path.push({ lat: firstPoint.lat, lng: firstPoint.lng });
}
return path;
},
// 导入导出方法
exportFences() {
try {
const text = JSON.stringify(this.deliveryFences, null, 2);
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(() => {
this.$message.success('配送区域JSON已复制到剪贴板');
}).catch(() => {
window.prompt('复制以下JSON:', text);
});
} else {
window.prompt('复制以下JSON:', text);
}
} catch (error) {
this.$message.error('导出失败');
console.error('导出配送区域失败:', error);
}
},
importFences() {
this.importText = '';
this.importDialogVisible = true;
},
confirmImport() {
try {
const data = JSON.parse(this.importText || '[]');
if (!Array.isArray(data)) {
this.$message.error('格式错误:应为数组');
return;
}
const valid = data.every(fence =>
fence && Array.isArray(fence.points) && fence.points.length >= 3
);
if (!valid) {
this.$message.error('数据不合法:每个区域至少包含3个点');
return;
}
this.deliveryFences = data;
this.updateDeliveryFencesData();
this.loadExistingFences();
this.importDialogVisible = false;
this.$message.success('导入成功');
} catch (error) {
this.$message.error('导入失败:JSON解析错误');
console.error('导入配送区域失败:', error);
}
},
// 原有方法保持不变
getTimestamp(time) {
let timestamp = Date.parse(new Date('1970-01-01 ' + time + ':00'));
return timestamp;
},
getDeliveryTime(index, type) {
if (type == 1) {
return {
start: '00:00',
step: '00:05',
end: this.ruleForm.business[index][1] ? this.ruleForm.business[index][1] : '23:59',
}
} else {
return {
start: this.ruleForm.business[index][0] ? this.ruleForm.business[index][0] : '00:00',
step: '00:05',
end: '23:59'
}
}
},
getBusinessTime(index, type) {
if (type == 1) {
return {
start: '00:00',
step: '00:05',
end: this.ruleForm.business_time[index][1] ? this.ruleForm.business_time[index][1] : '23:59',
}
} else {
return {
start: this.ruleForm.business_time[index][0] ? this.ruleForm.business_time[index][0] : '00:00',
step: '00:05',
end: '23:59'
}
}
},
addBusiness() {
this.ruleForm.business.push(['', '']);
},
spliceBusiness(index) {
this.ruleForm.business.splice(index, 1);
},
addBusinessTime() {
this.ruleForm.business_time.push(['', '']);
},
spliceBusinessTime(index) {
this.ruleForm.business_time.splice(index, 1);
},
// 导出配送区域JSON
exportFences() {
try {
const text = JSON.stringify(this.deliveryFences, null, 2);
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(() => {
this.$message.success('配送区域JSON已复制到剪贴板');
}).catch(() => {
window.prompt('复制以下JSON:', text);
});
} else {
window.prompt('复制以下JSON:', text);
}
} catch (e) {
this.$message.error('导出失败');
console.error('导出配送区域失败:', e);
}
},
// 导入配送区域JSON
importFences() {
this.importText = '';
this.importDialogVisible = true;
},
// 确认导入
confirmImport() {
try {
const data = JSON.parse(this.importText || '[]');
if (!Array.isArray(data)) {
this.$message.error('格式错误:应为数组');
return;
}
const valid = data.every(f => f && Array.isArray(f.points) && f.points.length >= 3);
if (!valid) {
this.$message.error('数据不合法:每个区域至少包含3个点');
return;
}
this.deliveryFences = data;
this.ruleForm.delivery_fences = JSON.stringify(this.deliveryFences);
this.loadExistingFences();
this.importDialogVisible = false;
this.$message.success('导入成功');
} catch (e) {
this.$message.error('导入失败:JSON解析错误');
console.error('导入配送区域失败:', e);
}
},
// 编辑已有配送区域
editFence(index) {
try {
const fence = this.deliveryFences[index];
if (!fence || !Array.isArray(fence.points) || fence.points.length < 3) {
this.$message.error('该区域数据无效,无法编辑');
return;
}
// 取消当前绘制(如果正在绘制)
if (this.isDrawing) {
this.cancelDrawing();
}
console.log(`开始编辑区域${index + 1}:`, fence);
this.isDrawing = true;
this.editIndex = index;
// 复制点集并移除闭合尾点(如果存在)
const pts = fence.points.slice();
if (pts.length >= 2) {
const fp = pts[0], lp = pts[pts.length - 1];
if (fp.lat === lp.lat && fp.lng === lp.lng) {
pts.pop();
console.log('移除闭合点,剩余点数:', pts.length);
}
}
// 载入路径(创建新的点对象避免引用问题)
this.currentPath = pts.map(p => ({
lat: parseFloat(p.lat),
lng: parseFloat(p.lng)
}));
console.log('编辑模式载入点数:', this.currentPath.length);
// 清理当前绘制对象
if (this.currentPolygon && this.currentPolygon.setMap) {
try { this.currentPolygon.setMap(null); } catch (e) {}
}
this.currentPolygon = null;
if (this.drawingLine && this.drawingLine.setMap) {
try { this.drawingLine.setMap(null); } catch (e) {}
}
this.drawingLine = null;
// 渲染编辑状态的显示
this.updateDrawingLines();
this.createPolygon();
// 将地图中心移动到该区域
this.focusFence(index);
this.$message.info('编辑模式:在地图上点击添加新点,双击或点击“完成绘制”保存修改');
} catch (e) {
console.error('进入编辑模式失败:', e);
this.$message.error('进入编辑模式失败');
// 重置状态
this.isDrawing = false;
this.editIndex = null;
this.currentPath = [];
}
},
submitForm(formName) {
this.$refs[formName].validate((valid) => {
if (valid) {
// 检查是否设置了配送区域
if (this.ruleForm.skip === "0" && this.deliveryFences.length === 0) {
this.$message.warning('开启送货上门服务时,请至少设置一个配送区域');
return;
}
let data = {...this.ruleForm};
this.sendRequest('Retail/Xcx/storeSet', {
data: data,
success: (res) => {
if (res.status == 1) {
this.$message.success(res.message);
this.before_address = this.ruleForm.address;
} else {
this.$message.error(res.message);
}
},
})
} else {
this.$message.warning('请检查必填项');
}
})
}
},
mounted() {
// 获取基本设置
$.ajax({
url: '/index.php/Retail/Xcx/manager',
type: 'post',
success: (res) => {
if (res.status == 1) {
this.ruleForm = res.data;
this.before_address = res.data.address;
// 等待DOM更新后初始化地图
this.$nextTick(() => {
// 等待腾讯地图API完全加载
this.waitForTMapLoad();
});
} else {
this.$message.error(res.msg)
}
}
});
},
created() {
// 获取操作权限
var auth_list = {
delivery_fee: '/index.php/Retail/Xcx/distribution'
};
$.ajax({
url: '/index.php/Retail/Component/checkOperateAuth',
type: "post",
data: {
auth_list: JSON.stringify(auth_list),
},
success: (res) => {
if (res.status == 1) {
this.operate = res.data;
}
}
})
}
})
</script>