From 1f9454af3356f628c25c3e2e492869163731da56 Mon Sep 17 00:00:00 2001
From: puzhibing <393733352@qq.com>
Date: 星期五, 09 十月 2026 10:47:24 +0800
Subject: [PATCH] 修改bug

---
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_add.html                                        |    7 
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDeMapUtil.java                          |   64 +
 ManagementFBTravel/guns-admin/src/main/resources/application.yml                                                              |    2 
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/home.html                                                          |    9 
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TGaodeAccountServiceImpl.java      |   28 +
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_edit.html                                       |    7 
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/GDKeyMapper.java                            |   31 +
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapElectricFenceUtil.java                |  136 +++-
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDKeyManager.java                          |  349 ++++++++++++
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TGaodeAccountController.java |  164 ++++++
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapGeocodingUtil.java                    |   43 +
 ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount.js                            |  257 +++++++++
 ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount_info.js                       |  133 ++++
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TGaodeAccountMapper.java                    |   28 +
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount.html                            |   58 ++
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_add.html                        |   32 +
 ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_edit.html                       |   32 +
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TGaodeAccountMapper.xml             |   41 +
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TGaodeAccount.java                        |  153 +++++
 ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITGaodeAccountService.java              |   24 
 20 files changed, 1,535 insertions(+), 63 deletions(-)

diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TGaodeAccountController.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TGaodeAccountController.java
new file mode 100644
index 0000000..17039a0
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/controller/general/TGaodeAccountController.java
@@ -0,0 +1,164 @@
+package com.stylefeng.guns.modular.system.controller.general;
+
+import com.baomidou.mybatisplus.mapper.EntityWrapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.stylefeng.guns.core.base.controller.BaseController;
+import com.stylefeng.guns.core.base.tips.ErrorTip;
+import com.stylefeng.guns.core.common.constant.factory.PageFactory;
+import com.stylefeng.guns.core.log.LogObjectHolder;
+import com.stylefeng.guns.core.shiro.ShiroKit;
+import com.stylefeng.guns.core.util.SinataUtil;
+import com.stylefeng.guns.modular.system.model.TGaodeAccount;
+import com.stylefeng.guns.modular.system.service.ITGaodeAccountService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * 高德地图账号控制器
+ *
+ * @author stylefeng
+ * @Date 2026-09-21
+ */
+@Controller
+@RequestMapping("/tGaodeAccount")
+public class TGaodeAccountController extends BaseController {
+
+    private String PREFIX = "/system/tGaodeAccount/";
+
+    @Autowired
+    private ITGaodeAccountService tGaodeAccountService;
+
+    /**
+     * 跳转到高德地图账号首页
+     */
+    @RequestMapping("")
+    public String index() {
+        return PREFIX + "tGaodeAccount.html";
+    }
+
+    /**
+     * 跳转到添加高德地图账号
+     */
+    @RequestMapping("/tGaodeAccount_add")
+    public String tGaodeAccountAdd() {
+        return PREFIX + "tGaodeAccount_add.html";
+    }
+
+    /**
+     * 跳转到修改高德地图账号
+     */
+    @RequestMapping("/tGaodeAccount_update/{tGaodeAccountId}")
+    public String tGaodeAccountUpdate(@PathVariable Integer tGaodeAccountId, Model model) {
+        TGaodeAccount tGaodeAccount = tGaodeAccountService.selectById(tGaodeAccountId);
+        model.addAttribute("item", tGaodeAccount);
+        LogObjectHolder.me().set(tGaodeAccount);
+        return PREFIX + "tGaodeAccount_edit.html";
+    }
+
+    /**
+     * 获取高德地图账号列表
+     */
+    @RequestMapping(value = "/list")
+    @ResponseBody
+    public Object list(String gdKey, Integer useStatus, Integer status) {
+        Page<Map<String, Object>> page = new PageFactory<Map<String, Object>>().defaultPage();
+        page.setRecords(tGaodeAccountService.getAccountList(page, gdKey, useStatus, status));
+        return super.packForBT(page);
+    }
+
+    /**
+     * 新增高德地图账号
+     */
+    @RequestMapping(value = "/add")
+    @ResponseBody
+    public Object add(TGaodeAccount tGaodeAccount) {
+        if (SinataUtil.isEmpty(tGaodeAccount.getGdKey())) {
+            return new ErrorTip(500, "高德key不能为空");
+        }
+        //校验高德key是否重复
+        TGaodeAccount exist = tGaodeAccountService.selectOne(new EntityWrapper<TGaodeAccount>()
+                .eq("gdKey", tGaodeAccount.getGdKey())
+                .eq("delFlag", 0));
+        if (SinataUtil.isNotEmpty(exist)) {
+            return new ErrorTip(500, "该高德key已存在,请勿重复添加");
+        }
+        if (SinataUtil.isEmpty(tGaodeAccount.getUseStatus())) {
+            tGaodeAccount.setUseStatus(1);
+        }
+        if (SinataUtil.isEmpty(tGaodeAccount.getStatus())) {
+            tGaodeAccount.setStatus(1);
+        }
+        tGaodeAccount.setDelFlag(0);
+        tGaodeAccount.setInsertTime(new Date());
+        tGaodeAccount.setInsertUser(ShiroKit.getUser().getId());
+        tGaodeAccountService.insert(tGaodeAccount);
+        return SUCCESS_TIP;
+    }
+
+    /**
+     * 删除高德地图账号(逻辑删除)
+     */
+    @RequestMapping(value = "/delete")
+    @ResponseBody
+    public Object delete(@RequestParam Integer tGaodeAccountId) {
+        TGaodeAccount tGaodeAccount = tGaodeAccountService.selectById(tGaodeAccountId);
+        if (SinataUtil.isNotEmpty(tGaodeAccount)) {
+            tGaodeAccount.setDelFlag(1);
+            tGaodeAccount.setUpdateTime(new Date());
+            tGaodeAccount.setUpdateUser(ShiroKit.getUser().getId());
+            tGaodeAccountService.updateById(tGaodeAccount);
+        }
+        return SUCCESS_TIP;
+    }
+
+    /**
+     * 修改高德地图账号
+     */
+    @RequestMapping(value = "/update")
+    @ResponseBody
+    public Object update(TGaodeAccount tGaodeAccount) {
+        if (SinataUtil.isEmpty(tGaodeAccount.getGdKey())) {
+            return new ErrorTip(500, "高德key不能为空");
+        }
+        //校验高德key是否重复(排除自身)
+        TGaodeAccount exist = tGaodeAccountService.selectOne(new EntityWrapper<TGaodeAccount>()
+                .eq("gdKey", tGaodeAccount.getGdKey())
+                .eq("delFlag", 0)
+                .ne("id", tGaodeAccount.getId()));
+        if (SinataUtil.isNotEmpty(exist)) {
+            return new ErrorTip(500, "该高德key已存在,请勿重复添加");
+        }
+        tGaodeAccount.setUpdateTime(new Date());
+        tGaodeAccount.setUpdateUser(ShiroKit.getUser().getId());
+        tGaodeAccountService.updateById(tGaodeAccount);
+        return SUCCESS_TIP;
+    }
+
+    /**
+     * 操作高德地图账号(启用/禁用)
+     */
+    @RequestMapping(value = "/opt")
+    @ResponseBody
+    public Object opt(@RequestParam Integer tGaodeAccountId, @RequestParam Integer optType) {
+        TGaodeAccount tGaodeAccount = tGaodeAccountService.selectById(tGaodeAccountId);
+        if (SinataUtil.isNotEmpty(tGaodeAccount)) {
+            if (1 == optType.intValue()) {  //启用
+                tGaodeAccount.setStatus(1);
+            } else if (2 == optType.intValue()) {  //禁用
+                tGaodeAccount.setStatus(2);
+            }
+            tGaodeAccount.setUpdateTime(new Date());
+            tGaodeAccount.setUpdateUser(ShiroKit.getUser().getId());
+            tGaodeAccountService.updateById(tGaodeAccount);
+        }
+        return SUCCESS_TIP;
+    }
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/GDKeyMapper.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/GDKeyMapper.java
new file mode 100644
index 0000000..1fec0f6
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/GDKeyMapper.java
@@ -0,0 +1,31 @@
+package com.stylefeng.guns.modular.system.dao;
+
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
+
+import java.util.List;
+
+/**
+ * 高德地图key管理 Mapper(注解方式,无需XML)
+ */
+public interface GDKeyMapper {
+
+    /**
+     * 查询可用key(启用、未删除、未用完)
+     */
+    @Select("SELECT gdKey FROM t_gaode_account WHERE status = 1 AND delFlag = 0 AND useStatus <> 3")
+    List<String> selectAvailableKeys();
+
+    /**
+     * 查询已用完的key(用于每日凌晨重置校验)
+     */
+    @Select("SELECT gdKey FROM t_gaode_account WHERE status = 1 AND delFlag = 0 AND useStatus = 3")
+    List<String> selectExhaustedKeys();
+
+    /**
+     * 更新key的使用状态
+     */
+    @Update("UPDATE t_gaode_account SET useStatus = #{useStatus} WHERE gdKey = #{gdKey} AND delFlag = 0")
+    int updateUseStatus(@Param("gdKey") String gdKey, @Param("useStatus") Integer useStatus);
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TGaodeAccountMapper.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TGaodeAccountMapper.java
new file mode 100644
index 0000000..c1fa78e
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/TGaodeAccountMapper.java
@@ -0,0 +1,28 @@
+package com.stylefeng.guns.modular.system.dao;
+
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+import com.baomidou.mybatisplus.plugins.Page;
+import com.stylefeng.guns.modular.system.model.TGaodeAccount;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 高德地图账号 Mapper 接口
+ * </p>
+ *
+ * @author stylefeng
+ * @since 2026-09-21
+ */
+public interface TGaodeAccountMapper extends BaseMapper<TGaodeAccount> {
+
+    /**
+     * 根据条件查询高德地图账号列表
+     */
+    List<Map<String, Object>> getAccountList(Page<Map<String, Object>> page,
+                                             @Param("gdKey") String gdKey,
+                                             @Param("useStatus") Integer useStatus,
+                                             @Param("status") Integer status);
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TGaodeAccountMapper.xml b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TGaodeAccountMapper.xml
new file mode 100644
index 0000000..88ada9e
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/dao/mapping/TGaodeAccountMapper.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.stylefeng.guns.modular.system.dao.TGaodeAccountMapper">
+
+    <!-- 通用查询映射结果 -->
+    <resultMap id="BaseResultMap" type="com.stylefeng.guns.modular.system.model.TGaodeAccount">
+        <id column="id" property="id" />
+        <result column="gdKey" property="gdKey" />
+        <result column="useStatus" property="useStatus" />
+        <result column="status" property="status" />
+        <result column="delFlag" property="delFlag" />
+        <result column="insertTime" property="insertTime" />
+        <result column="insertUser" property="insertUser" />
+        <result column="updateTime" property="updateTime" />
+        <result column="updateUser" property="updateUser" />
+    </resultMap>
+
+    <!-- 通用查询结果列 -->
+    <sql id="Base_Column_List">
+        id, gdKey, useStatus, status, delFlag, insertTime, insertUser, updateTime, updateUser
+    </sql>
+
+    <!--根据条件查询高德地图账号列表-->
+    <select id="getAccountList" resultType="map" parameterType="com.baomidou.mybatisplus.plugins.Page">
+        SELECT * FROM t_gaode_account
+        <where>
+            delFlag = 0
+            <if test="gdKey != null and gdKey != ''">
+                and gdKey LIKE CONCAT('%',#{gdKey},'%')
+            </if>
+            <if test="useStatus != null and useStatus != ''">
+                and useStatus = #{useStatus}
+            </if>
+            <if test="status != null and status != ''">
+                and status = #{status}
+            </if>
+        </where>
+        order by id desc
+    </select>
+
+</mapper>
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TGaodeAccount.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TGaodeAccount.java
new file mode 100644
index 0000000..a93086b
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/model/TGaodeAccount.java
@@ -0,0 +1,153 @@
+package com.stylefeng.guns.modular.system.model;
+
+import com.baomidou.mybatisplus.enums.IdType;
+import java.util.Date;
+import com.baomidou.mybatisplus.annotations.TableId;
+import com.baomidou.mybatisplus.activerecord.Model;
+import com.baomidou.mybatisplus.annotations.TableName;
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 高德地图账号
+ * </p>
+ *
+ * @author stylefeng
+ * @since 2026-09-21
+ */
+@TableName("t_gaode_account")
+public class TGaodeAccount extends Model<TGaodeAccount> {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键id
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 高德的key
+     */
+    private String gdKey;
+    /**
+     * 使用状态  1=未使用  2=使用中  3=已用完
+     */
+    private Integer useStatus;
+    /**
+     * 状态  1=启用  2=禁用
+     */
+    private Integer status;
+    /**
+     * 删除状态  0=未删除  1=已删除
+     */
+    private Integer delFlag;
+    /**
+     * 添加时间
+     */
+    private Date insertTime;
+    /**
+     * 添加人
+     */
+    private Integer insertUser;
+    /**
+     * 修改时间
+     */
+    private Date updateTime;
+    /**
+     * 修改人
+     */
+    private Integer updateUser;
+
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getGdKey() {
+        return gdKey;
+    }
+
+    public void setGdKey(String gdKey) {
+        this.gdKey = gdKey;
+    }
+
+    public Integer getUseStatus() {
+        return useStatus;
+    }
+
+    public void setUseStatus(Integer useStatus) {
+        this.useStatus = useStatus;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(Integer delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public Date getInsertTime() {
+        return insertTime;
+    }
+
+    public void setInsertTime(Date insertTime) {
+        this.insertTime = insertTime;
+    }
+
+    public Integer getInsertUser() {
+        return insertUser;
+    }
+
+    public void setInsertUser(Integer insertUser) {
+        this.insertUser = insertUser;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Integer getUpdateUser() {
+        return updateUser;
+    }
+
+    public void setUpdateUser(Integer updateUser) {
+        this.updateUser = updateUser;
+    }
+
+    @Override
+    protected Serializable pkVal() {
+        return this.id;
+    }
+
+    @Override
+    public String toString() {
+        return "TGaodeAccount{" +
+        "id=" + id +
+        ", gdKey=" + gdKey +
+        ", useStatus=" + useStatus +
+        ", status=" + status +
+        ", delFlag=" + delFlag +
+        ", insertTime=" + insertTime +
+        ", insertUser=" + insertUser +
+        ", updateTime=" + updateTime +
+        ", updateUser=" + updateUser +
+        "}";
+    }
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITGaodeAccountService.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITGaodeAccountService.java
new file mode 100644
index 0000000..b2b61a2
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/ITGaodeAccountService.java
@@ -0,0 +1,24 @@
+package com.stylefeng.guns.modular.system.service;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.IService;
+import com.stylefeng.guns.modular.system.model.TGaodeAccount;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 高德地图账号 服务类
+ * </p>
+ *
+ * @author stylefeng
+ * @since 2026-09-21
+ */
+public interface ITGaodeAccountService extends IService<TGaodeAccount> {
+
+    /**
+     * 根据条件查询高德地图账号列表
+     */
+    List<Map<String, Object>> getAccountList(Page<Map<String, Object>> page, String gdKey, Integer useStatus, Integer status);
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TGaodeAccountServiceImpl.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TGaodeAccountServiceImpl.java
new file mode 100644
index 0000000..4041178
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/service/impl/TGaodeAccountServiceImpl.java
@@ -0,0 +1,28 @@
+package com.stylefeng.guns.modular.system.service.impl;
+
+import com.baomidou.mybatisplus.plugins.Page;
+import com.baomidou.mybatisplus.service.impl.ServiceImpl;
+import com.stylefeng.guns.modular.system.dao.TGaodeAccountMapper;
+import com.stylefeng.guns.modular.system.model.TGaodeAccount;
+import com.stylefeng.guns.modular.system.service.ITGaodeAccountService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 高德地图账号 服务实现类
+ * </p>
+ *
+ * @author stylefeng
+ * @since 2026-09-21
+ */
+@Service
+public class TGaodeAccountServiceImpl extends ServiceImpl<TGaodeAccountMapper, TGaodeAccount> implements ITGaodeAccountService {
+
+    @Override
+    public List<Map<String, Object>> getAccountList(Page<Map<String, Object>> page, String gdKey, Integer useStatus, Integer status) {
+        return this.baseMapper.getAccountList(page, gdKey, useStatus, status);
+    }
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDKeyManager.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDKeyManager.java
new file mode 100644
index 0000000..f42b2ca
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDKeyManager.java
@@ -0,0 +1,349 @@
+package com.stylefeng.guns.modular.system.util;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.stylefeng.guns.modular.system.dao.GDKeyMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import org.springframework.web.client.RestTemplate;
+
+import javax.annotation.PostConstruct;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * 高德地图key管理器
+ * <p>
+ * 功能:
+ * 1. key池管理:从 t_gaode_account 表加载可用key(启用、未删除、未用完),轮询获取;
+ *    表为空或全部用尽时降级使用兜底key(原硬编码key)。
+ * 2. 自动切换:调用方检测到key"次数用完"后调用 reportExhausted 上报,
+ *    管理器将key移出内存池并置库表 useStatus=3(已用完)。
+ * 3. 每日凌晨重置校验:每天 00:00 将 useStatus=3 的key重置为未使用并放回池,
+ *    随后调用高德最轻量接口校验配额是否真正恢复;未恢复的key重新标记已用完,
+ *    进入延迟重试队列,每30分钟校验一次直到恢复额度。
+ * 4. 兜底key:当天用完仅内存禁用,次日凌晨自动恢复;不写库(表内无对应记录)。
+ */
+@Component
+public class GDKeyManager {
+
+    private static final Logger logger = LoggerFactory.getLogger(GDKeyManager.class);
+
+    /**
+     * 兜底key(原硬编码key):管理端/用户端
+     */
+    public static final String FALLBACK_KEY = "39b31fa22955efa8fce9eed487241db9";
+
+    /**
+     * 配额校验接口:最轻量的通用Web服务接口,每次仅消耗1次配额
+     */
+    private static final String VERIFY_URL = "https://restapi.amap.com/v3/geocode/geo?output=JSON&address=%E5%8C%97%E4%BA%AC%E5%B8%82&key=";
+
+    @Autowired
+    private GDKeyMapper gdKeyMapper;
+
+    @Autowired
+    private RestTemplate restTemplate;
+
+    /**
+     * 内存可用key池(refreshPool整体替换,保证getKey不会看到clear/addAll中间态)
+     */
+    private volatile List<String> availableKeys = new CopyOnWriteArrayList<>();
+
+    /**
+     * 轮询下标
+     */
+    private final AtomicInteger index = new AtomicInteger(0);
+
+    /**
+     * 延迟校验队列:key -> 已重试次数(每日凌晨校验未恢复的key)
+     */
+    private final ConcurrentHashMap<String, Integer> pendingVerifyKeys = new ConcurrentHashMap<>();
+
+    /**
+     * 兜底key当日是否已用完
+     */
+    private volatile boolean fallbackExhausted = false;
+
+    /**
+     * 已标记"使用中"(useStatus=2)的key集合,避免热路径每次取用都写库
+     */
+    private final Set<String> inUseKeys = ConcurrentHashMap.newKeySet();
+
+    @PostConstruct
+    public void init() {
+        refreshPool();
+    }
+
+    /**
+     * 刷新可用key池
+     */
+    public synchronized void refreshPool() {
+        try {
+            List<String> keys = gdKeyMapper.selectAvailableKeys();
+            List<String> newPool = new CopyOnWriteArrayList<>();
+            if (keys != null) {
+                newPool.addAll(keys);
+            }
+            // 整体替换,避免clear/addAll中间态导致getKey短暂看到空池误降级兜底key
+            availableKeys = newPool;
+            logger.info("[GDKeyManager] 高德key池刷新完成,可用key数:{}", newPool.size());
+        } catch (Exception e) {
+            // 表不存在(用户端/司机端未建表时)等异常:降级使用兜底key,不影响系统运行
+            logger.warn("[GDKeyManager] 加载高德key失败(t_gaode_account表可能不存在),降级使用兜底key", e);
+            availableKeys = new CopyOnWriteArrayList<>();
+        }
+    }
+
+    /**
+     * 获取一个可用key:池非空轮询池内key;池空使用兜底key(当日未用完时)
+     */
+    public String getKey() {
+        List<String> pool = availableKeys;
+        if (!pool.isEmpty()) {
+            String key = pickFromPool(pool);
+            markInUse(key);
+            return key;
+        }
+        if (!fallbackExhausted) {
+            return FALLBACK_KEY;
+        }
+        // 兜底key当日也已用完:尝试刷新池(可能有新录入的key)
+        refreshPool();
+        pool = availableKeys;
+        if (!pool.isEmpty()) {
+            String key = pickFromPool(pool);
+            markInUse(key);
+            return key;
+        }
+        return FALLBACK_KEY;
+    }
+
+    /**
+     * 从内存池轮询取一个key(使用调用方传入的池快照,避免与定时刷新交叉导致越界)
+     */
+    private String pickFromPool(List<String> pool) {
+        int i = Math.abs(index.getAndIncrement() % pool.size());
+        return pool.get(i);
+    }
+
+    /**
+     * 将表内key标记为"使用中"(useStatus=2):
+     * 仅key首次被取用时写库一次;兜底key不写库;写库失败不影响取key流程。
+     */
+    private void markInUse(String key) {
+        if (key == null || FALLBACK_KEY.equals(key) || inUseKeys.contains(key)) {
+            return;
+        }
+        try {
+            gdKeyMapper.updateUseStatus(key, 2);
+            inUseKeys.add(key);
+            logger.info("[GDKeyManager] 高德key[{}]开始使用,已标记为使用中", key);
+        } catch (Exception e) {
+            // 表不存在等异常:本次不标记,下次取用再尝试,不影响业务
+            logger.warn("[GDKeyManager] 标记高德key[{}]使用中失败(表可能不存在),不影响使用", key);
+        }
+    }
+
+    /**
+     * 定时刷新key池:每5分钟一次,让管理后台新录入的key及时生效
+     */
+    @Scheduled(fixedDelay = 5 * 60 * 1000, initialDelay = 60 * 1000)
+    public void scheduledRefreshPool() {
+        refreshPool();
+    }
+
+    /**
+     * 上报某个key次数用完:
+     * 表内key -> 移出内存池 + 置库表 useStatus=3;
+     * 兜底key -> 仅内存当日禁用(不写库),次日凌晨自动恢复。
+     */
+    public void reportExhausted(String usedKey) {
+        if (usedKey == null || usedKey.isEmpty()) {
+            return;
+        }
+        availableKeys.remove(usedKey);
+        inUseKeys.remove(usedKey);
+        if (FALLBACK_KEY.equals(usedKey)) {
+            fallbackExhausted = true;
+            logger.warn("[GDKeyManager] 兜底key次数已用完,今日禁用,次日凌晨自动恢复");
+            return;
+        }
+        try {
+            gdKeyMapper.updateUseStatus(usedKey, 3);
+            logger.warn("[GDKeyManager] 高德key[{}]次数用完,已标记为已用完并移出key池", usedKey);
+        } catch (Exception e) {
+            logger.warn("[GDKeyManager] 更新高德key[{}]使用状态失败(表可能不存在),仅内存剔除", usedKey);
+        }
+    }
+
+    /**
+     * 判断Web服务API响应是否为"次数用完/不可用"(依据infocode)
+     */
+    public static boolean isWebKeyExhausted(JSONObject resp) {
+        if (resp == null) {
+            return false;
+        }
+        String infocode = resp.getString("infocode");
+        if (infocode == null || infocode.isEmpty()) {
+            return false;
+        }
+        switch (infocode) {
+            case "10001": // key不正确或过期
+            case "10003": // 超过每日配额
+            case "10004": // 访问过于频繁
+            case "10005": // 超出每秒访问量限制
+            case "10010": // 权限不足
+            case "10012": // 服务未开放/权限不足
+            case "10019": // 使用配额已用尽
+            case "10020": // 并发超限
+            case "10044": // 签名错误/未开通
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 判断猎鹰API响应是否为"次数用完"(依据errcode/errmsg)
+     */
+    public static boolean isFalconExhausted(JSONObject resp) {
+        if (resp == null) {
+            return false;
+        }
+        int errcode = resp.getIntValue("errcode");
+        if (errcode == 10000) {
+            return false;
+        }
+        if (errcode == 20001) {
+            return true; // 权限不足
+        }
+        String errmsg = resp.getString("errmsg");
+        if (errmsg == null) {
+            return false;
+        }
+        return errmsg.contains("配额") || errmsg.contains("上限") || errmsg.contains("次数")
+                || errmsg.contains("用完") || errmsg.contains("超限")
+                || errmsg.contains("quota") || errmsg.contains("limit");
+    }
+
+    // ==================== 每日凌晨重置 + API校验恢复额度 ====================
+
+    /**
+     * 每日凌晨 00:00 自动执行:
+     * 1. 将 useStatus=3(已用完)的key重置为未使用并放回内存池;
+     * 2. 调用高德API校验配额是否真正恢复;
+     * 3. 未恢复的key重新标记已用完,进入延迟重试队列,直到恢复额度。
+     */
+    @Scheduled(cron = "0 0 0 * * ?")
+    public void dailyResetAndVerify() {
+        logger.info("[GDKeyManager] 开始每日高德key配额重置校验");
+        // 兜底key当日禁用标记次日自动恢复
+        fallbackExhausted = false;
+        List<String> exhaustedKeys;
+        try {
+            exhaustedKeys = gdKeyMapper.selectExhaustedKeys();
+        } catch (Exception e) {
+            logger.warn("[GDKeyManager] 查询已用完key失败(表可能不存在),跳过重置校验", e);
+            return;
+        }
+        if (exhaustedKeys == null || exhaustedKeys.isEmpty()) {
+            logger.info("[GDKeyManager] 无已用完的key,跳过重置校验");
+            return;
+        }
+        for (String gdKey : exhaustedKeys) {
+            // 1. 先重置为未使用
+            try {
+                gdKeyMapper.updateUseStatus(gdKey, 1);
+            } catch (Exception e) {
+                logger.warn("[GDKeyManager] 重置key[{}]使用状态失败", gdKey, e);
+            }
+            // 2. 调用API校验是否真正恢复额度
+            boolean recovered = verifyQuota(gdKey);
+            if (recovered) {
+                if (!availableKeys.contains(gdKey)) {
+                    availableKeys.add(gdKey);
+                }
+                pendingVerifyKeys.remove(gdKey);
+                logger.info("[GDKeyManager] 高德key[{}]配额已恢复,重新加入key池", gdKey);
+            } else {
+                // 未恢复:重新标记已用完,进入延迟重试队列
+                try {
+                    gdKeyMapper.updateUseStatus(gdKey, 3);
+                } catch (Exception e) {
+                    logger.warn("[GDKeyManager] 回写key[{}]已用完状态失败", gdKey, e);
+                }
+                availableKeys.remove(gdKey);
+                pendingVerifyKeys.put(gdKey, 0);
+                logger.warn("[GDKeyManager] 高德key[{}]配额尚未恢复,进入延迟重试队列", gdKey);
+            }
+        }
+    }
+
+    /**
+     * 延迟重试任务:每30分钟校验一次待恢复的key,直到恢复额度为止
+     */
+    @Scheduled(fixedDelay = 30 * 60 * 1000, initialDelay = 30 * 60 * 1000)
+    public void retryPendingKeys() {
+        if (pendingVerifyKeys.isEmpty()) {
+            return;
+        }
+        for (String gdKey : new ArrayList<>(pendingVerifyKeys.keySet())) {
+            boolean recovered = verifyQuota(gdKey);
+            if (recovered) {
+                try {
+                    gdKeyMapper.updateUseStatus(gdKey, 1);
+                } catch (Exception e) {
+                    logger.warn("[GDKeyManager] 恢复key[{}]使用状态失败", gdKey, e);
+                }
+                if (!availableKeys.contains(gdKey)) {
+                    availableKeys.add(gdKey);
+                }
+                pendingVerifyKeys.remove(gdKey);
+                logger.info("[GDKeyManager] 高德key[{}]延迟校验通过,配额已恢复,重新加入key池", gdKey);
+            } else {
+                int count = pendingVerifyKeys.merge(gdKey, 1, Integer::sum);
+                logger.warn("[GDKeyManager] 高德key[{}]配额仍未恢复(已校验{}次),继续等待", gdKey, count);
+            }
+        }
+    }
+
+    /**
+     * 调用高德最轻量接口校验配额是否恢复
+     *
+     * @return true=已恢复(或无法判断,保守放行);false=明确未恢复(配额类错误)
+     */
+    private boolean verifyQuota(String gdKey) {
+        try {
+            String resp = restTemplate.getForObject(VERIFY_URL + gdKey, String.class);
+            JSONObject json = JSON.parseObject(resp);
+            String status = json.getString("status");
+            String infocode = json.getString("infocode");
+            if ("1".equals(status) && "10000".equals(infocode)) {
+                return true;
+            }
+            // 权限类错误:该key未开通Web服务校验权限(如猎鹰专用key),无法判断配额,按已恢复处理
+            if ("10044".equals(infocode) || "10012".equals(infocode)
+                    || "10002".equals(infocode) || "10010".equals(infocode)) {
+                logger.info("[GDKeyManager] 高德key[{}]无Web服务校验权限(infocode={}),按已恢复处理", gdKey, infocode);
+                return true;
+            }
+            // 配额类错误:明确未恢复
+            if ("10001".equals(infocode) || "10003".equals(infocode) || "10019".equals(infocode)) {
+                return false;
+            }
+            // 其他错误(限流/网络等):保守放行,真实调用失败时会被自动切换机制再次标记
+            return true;
+        } catch (Exception e) {
+            logger.warn("[GDKeyManager] 校验key[{}]配额异常,按已恢复处理", gdKey, e);
+            return true;
+        }
+    }
+}
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapElectricFenceUtil.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapElectricFenceUtil.java
index 8f17281..04e4121 100644
--- a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapElectricFenceUtil.java
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapElectricFenceUtil.java
@@ -34,9 +34,98 @@
     @Autowired
     private IGDInterfaceService gdInterfaceService;
 
-    private String key = "ca723c3c8a78962a7751129ae035dc9d";
+    @Autowired
+    private GDKeyManager gdKeyManager;
 
     private JSONArray jsonArray = new JSONArray();
+
+    /**
+     * 执行GET请求:key次数用完时自动切换可用key重试
+     */
+    private String doGetWithRetry(String baseUrl) {
+        String lastResp = null;
+        int maxAttempts = 5;
+        for (int i = 0; i < maxAttempts; i++) {
+            String key = gdKeyManager.getKey();
+            String url = baseUrl + (baseUrl.contains("?") ? "&" : "?") + "key=" + key;
+            String resp = restTemplate.getForObject(url, String.class);
+            lastResp = resp;
+            JSONObject jsonObject;
+            try {
+                jsonObject = JSON.parseObject(resp);
+            } catch (Exception e) {
+                return resp;
+            }
+            if (GDKeyManager.isWebKeyExhausted(jsonObject)) {
+                gdKeyManager.reportExhausted(key);
+                continue;
+            }
+            return resp;
+        }
+        return lastResp;
+    }
+
+    /**
+     * 执行POST请求(JSON体):key次数用完时自动切换可用key重试
+     */
+    private String doPostJsonWithRetry(String baseUrl, String jsonBody) {
+        String lastResp = null;
+        int maxAttempts = 5;
+        HttpHeaders headers = new HttpHeaders();
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+        headers.setContentType(type);
+        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
+        for (int i = 0; i < maxAttempts; i++) {
+            String key = gdKeyManager.getKey();
+            String url = baseUrl + (baseUrl.contains("?") ? "&" : "?") + "key=" + key;
+            HttpEntity<String> formEntity = new HttpEntity<>(jsonBody, headers);
+            String resp = restTemplate.postForObject(url, formEntity, String.class);
+            lastResp = resp;
+            JSONObject jsonObject;
+            try {
+                jsonObject = JSON.parseObject(resp);
+            } catch (Exception e) {
+                return resp;
+            }
+            if (GDKeyManager.isWebKeyExhausted(jsonObject)) {
+                gdKeyManager.reportExhausted(key);
+                continue;
+            }
+            return resp;
+        }
+        return lastResp;
+    }
+
+    /**
+     * 执行PATCH请求(JSON体):key次数用完时自动切换可用key重试
+     */
+    private String doPatchJsonWithRetry(String baseUrl, String jsonBody) {
+        String lastResp = null;
+        int maxAttempts = 5;
+        HttpHeaders headers = new HttpHeaders();
+        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
+        headers.setContentType(type);
+        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
+        for (int i = 0; i < maxAttempts; i++) {
+            String key = gdKeyManager.getKey();
+            String url = baseUrl + (baseUrl.contains("?") ? "&" : "?") + "key=" + key;
+            HttpEntity<String> formEntity = new HttpEntity<>(jsonBody, headers);
+            String resp = restTemplate.patchForObject(url, formEntity, String.class);
+            lastResp = resp;
+            JSONObject jsonObject;
+            try {
+                jsonObject = JSON.parseObject(resp);
+            } catch (Exception e) {
+                return resp;
+            }
+            if (GDKeyManager.isWebKeyExhausted(jsonObject)) {
+                gdKeyManager.reportExhausted(key);
+                continue;
+            }
+            return resp;
+        }
+        return lastResp;
+    }
 
 
     @Bean
@@ -82,14 +171,7 @@
             json.put("alert_condition", "enter;leave");
             json.put("desc", id);
 
-            HttpHeaders headers = new HttpHeaders();
-            MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
-            headers.setContentType(type);
-            headers.add("Accept", MediaType.APPLICATION_JSON.toString());
-            HttpEntity<String> formEntity = new HttpEntity<>(json.toString(), headers);
-
-            String url = "https://restapi.amap.com/v4/geofence/meta?key=" + key;
-            String js = restTemplate.postForObject(url, formEntity, String.class);
+            String js = doPostJsonWithRetry("https://restapi.amap.com/v4/geofence/meta", json.toString());
             JSONObject jsonObject = JSON.parseObject(js);
             JSONObject data = jsonObject.getJSONObject("data");
             String status = data.getString("status");
@@ -132,8 +214,8 @@
      * @return
      */
     public String findElectricFenc(String gid){
-        String url = "https://restapi.amap.com/v4/geofence/meta?key=" + key + "&gid=" + gid;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v4/geofence/meta?gid=" + gid;
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         JSONObject data = jsonObject.getJSONObject("data");
         JSONArray rs_list = data.getJSONArray("rs_list");
@@ -149,8 +231,8 @@
      * 查询以创建的所有电子围栏
      */
     public String findElectricFenc(String center, String radius, String points){
-        String url = "https://restapi.amap.com/v4/geofence/meta?key=" + key;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v4/geofence/meta";
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         JSONObject data = jsonObject.getJSONObject("data");
 
@@ -186,8 +268,8 @@
         if(page == 1){
             jsonArray = new JSONArray();
         }
-        String url = "https://restapi.amap.com/v4/geofence/meta?key=" + key + "&page_no=" + page + "&page_size=" + 30;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v4/geofence/meta?page_no=" + page + "&page_size=" + 30;
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         JSONObject data = jsonObject.getJSONObject("data");
         JSONArray rs_list = data.getJSONArray("rs_list");
@@ -275,14 +357,8 @@
         json.put("alert_condition", "enter;leave");
         json.put("desc", id + "围栏更新描述");
 
-        HttpHeaders headers = new HttpHeaders();
-        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
-        headers.setContentType(type);
-        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
-        HttpEntity<String> formEntity = new HttpEntity<>(json.toString(), headers);
-
-        String url = "https://restapi.amap.com/v4/geofence/meta?key=" + key + "&gid=" + gid;
-        String s = restTemplate.patchForObject(url, formEntity, String.class);
+        String url = "https://restapi.amap.com/v4/geofence/meta?gid=" + gid;
+        String s = doPatchJsonWithRetry(url, json.toString());
         System.out.println(s);
 
         gdInterfaceService.saveData("https://restapi.amap.com/v4/geofence/meta", "更新电子围栏");
@@ -304,8 +380,8 @@
             diu = "B78F99DD-2496-4A43-843B-172CDA2D9798";
         }
         locations = locations + "," + (new Date().getTime() / 1000);
-        String url = "https://restapi.amap.com/v4/geofence/status?key=" + key + "&diu=" + diu + "&locations=" + locations;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v4/geofence/status?diu=" + diu + "&locations=" + locations;
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         List<String> ids = new ArrayList<>();
         JSONObject data = jsonObject.getJSONObject("data");
@@ -334,7 +410,7 @@
      * @return
      */
     public boolean deleteElectricFenc(String gid){
-        restTemplate.delete("https://restapi.amap.com/v4/geofence/meta?key={1}&gid={2}", key, gid);
+        restTemplate.delete("https://restapi.amap.com/v4/geofence/meta?key={1}&gid={2}", gdKeyManager.getKey(), gid);
         System.out.println("删除:" );
 
         gdInterfaceService.saveData("https://restapi.amap.com/v4/geofence/meta", "删除电子围栏");
@@ -351,9 +427,9 @@
      * @return
      */
     public Map<String, String> getDistance(String origins, String destination, Integer type){
-        String url = "https://restapi.amap.com/v3/distance?key=" + key + "&origins=" + origins + "&destination=" + destination +
+        String url = "https://restapi.amap.com/v3/distance?origins=" + origins + "&destination=" + destination +
                 "&type=" + type;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         String status = jsonObject.getString("status");
 
@@ -381,9 +457,9 @@
      * @return
      */
     public Map<String, String> getDriving(String origins, String destination, String waypoints){
-        String url = "https://restapi.amap.com/v3/direction/driving?key=" + key + "&origin=" + origins + "&destination=" + destination +
+        String url = "https://restapi.amap.com/v3/direction/driving?origin=" + origins + "&destination=" + destination +
                 "&waypoints=" + waypoints + "&extensions=base&strategy=0";
-        String forObject = restTemplate.getForObject(url, String.class);
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         String status = jsonObject.getString("status");
 
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapGeocodingUtil.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapGeocodingUtil.java
index 5845ae2..33e97e5 100644
--- a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapGeocodingUtil.java
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GDMapGeocodingUtil.java
@@ -20,13 +20,40 @@
 @Component
 public class GDMapGeocodingUtil {
 
-    private String key = "ca723c3c8a78962a7751129ae035dc9d";
-
     @Autowired
     private RestTemplate restTemplate;
 
     @Autowired
     private IGDInterfaceService gdInterfaceService;
+
+    @Autowired
+    private GDKeyManager gdKeyManager;
+
+    /**
+     * 执行GET请求:key次数用完时自动切换可用key重试
+     */
+    private String doGetWithRetry(String baseUrl) {
+        String lastResp = null;
+        int maxAttempts = 5;
+        for (int i = 0; i < maxAttempts; i++) {
+            String key = gdKeyManager.getKey();
+            String url = baseUrl + (baseUrl.contains("?") ? "&" : "?") + "key=" + key;
+            String resp = restTemplate.getForObject(url, String.class);
+            lastResp = resp;
+            JSONObject jsonObject;
+            try {
+                jsonObject = JSON.parseObject(resp);
+            } catch (Exception e) {
+                return resp;
+            }
+            if (GDKeyManager.isWebKeyExhausted(jsonObject)) {
+                gdKeyManager.reportExhausted(key);
+                continue;
+            }
+            return resp;
+        }
+        return lastResp;
+    }
 
 
     /**
@@ -55,9 +82,9 @@
             return map;
         }
 
-        String url = "https://restapi.amap.com/v3/geocode/geo?key=" + key + "&output=JSON";
+        String url = "https://restapi.amap.com/v3/geocode/geo?output=JSON";
         url += "&address=" + province + (ToolUtil.isNotEmpty(city) ? city : "") + (ToolUtil.isNotEmpty(county) ? county : "") + (ToolUtil.isNotEmpty(address) ? address : "");
-        String forObject = restTemplate.getForObject(url, String.class);
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         String status = jsonObject.getString("status");
         List<String> list = new ArrayList<>();
@@ -80,8 +107,8 @@
 
     public Map<String, Object> geocoding(String address){
         Map<String, Object> map = new HashMap<>();
-        String url = "https://restapi.amap.com/v3/geocode/geo?key=" + key + "&output=JSON&address=" + address;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v3/geocode/geo?output=JSON&address=" + address;
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         String status = jsonObject.getString("status");
         List<String> list = new ArrayList<>();
@@ -110,8 +137,8 @@
      * @throws Exception
      */
     public Map<String, String> geocode(String lon, String lan) throws Exception{
-        String url = "https://restapi.amap.com/v3/geocode/regeo?key=" + key + "&location=" + lon + "," + lan;
-        String forObject = restTemplate.getForObject(url, String.class);
+        String url = "https://restapi.amap.com/v3/geocode/regeo?location=" + lon + "," + lan;
+        String forObject = doGetWithRetry(url);
         JSONObject jsonObject = JSON.parseObject(forObject);
         Map<String, String> map = new HashMap<>();
 
diff --git a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDeMapUtil.java b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDeMapUtil.java
index 89d066f..ed6452f 100644
--- a/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDeMapUtil.java
+++ b/ManagementFBTravel/guns-admin/src/main/java/com/stylefeng/guns/modular/system/util/GaoDeMapUtil.java
@@ -1,6 +1,8 @@
 package com.stylefeng.guns.modular.system.util;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.stylefeng.guns.core.util.SpringContextHolder;
 import org.apache.http.HttpEntity;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -25,35 +27,57 @@
     }
 
     /**
+     * 获取GDKeyManager(非Spring环境下返回null,如main测试)
+     */
+    private static GDKeyManager getKeyManager() {
+        try {
+            return SpringContextHolder.getBean(GDKeyManager.class);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
      * 根据地址查询经纬度
+     * key次数用完时自动切换可用key重试
      *
      * @param address
      * @return
      */
     public static JSONObject getLngAndLat(String address) {
         JSONObject positionObj = new JSONObject();
+        GDKeyManager keyManager = getKeyManager();
 
-        try {
-            // 拼接请求高德的url
-            String url = "http://restapi.amap.com/v3/geocode/geo?address=" + address + "&output=JSON&key=" + "ca723c3c8a78962a7751129ae035dc9d";
-            // 请求高德接口
-            String result = sendHttpGet(url);
-            JSONObject resultJOSN = JSONObject.parseObject(result);
-            System.out.println("高德接口返回原始数据:");
-            System.out.println(resultJOSN);
-            JSONArray geocodesArray = resultJOSN.getJSONArray("geocodes");
-            if (geocodesArray.size() > 0) {
-                String position = geocodesArray.getJSONObject(0).getString("location");
-                String[] lngAndLat = position.split(",");
-                String longitude = lngAndLat[0];
-                String latitude = lngAndLat[1];
-                positionObj.put("longitude", longitude);
-                positionObj.put("latitude", latitude);
+        int maxAttempts = 5;
+        for (int i = 0; i < maxAttempts; i++) {
+            String key = keyManager != null ? keyManager.getKey() : GDKeyManager.FALLBACK_KEY;
+            try {
+                // 拼接请求高德的url
+                String url = "http://restapi.amap.com/v3/geocode/geo?address=" + address + "&output=JSON&key=" + key;
+                // 请求高德接口
+                String result = sendHttpGet(url);
+                JSONObject resultJOSN = JSON.parseObject(result);
+                System.out.println("高德接口返回原始数据:");
+                System.out.println(resultJOSN);
+                if (GDKeyManager.isWebKeyExhausted(resultJOSN)) {
+                    if (keyManager != null) {
+                        keyManager.reportExhausted(key);
+                    }
+                    continue;
+                }
+                JSONArray geocodesArray = resultJOSN.getJSONArray("geocodes");
+                if (geocodesArray != null && geocodesArray.size() > 0) {
+                    String position = geocodesArray.getJSONObject(0).getString("location");
+                    String[] lngAndLat = position.split(",");
+                    String longitude = lngAndLat[0];
+                    String latitude = lngAndLat[1];
+                    positionObj.put("longitude", longitude);
+                    positionObj.put("latitude", latitude);
+                }
+                break;
+            } catch (Exception e) {
+                e.printStackTrace();
             }
-            geocodesArray.getJSONObject(0).getString("location");
-
-        } catch (Exception e) {
-            e.printStackTrace();
         }
         return positionObj;
     }
diff --git a/ManagementFBTravel/guns-admin/src/main/resources/application.yml b/ManagementFBTravel/guns-admin/src/main/resources/application.yml
index 6dbfd74..6d4f4b9 100644
--- a/ManagementFBTravel/guns-admin/src/main/resources/application.yml
+++ b/ManagementFBTravel/guns-admin/src/main/resources/application.yml
@@ -66,7 +66,7 @@
 
 #spring:
 #  datasource:
-#    url: jdbc:mysql://127.0.0.1:3306/fbtravel?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
+#    url: jdbc:mysql://192.168.110.80:3306/fbtravel?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=GMT%2B8
 #    username: root
 #    password: 123456
 #    db-name: oktravel #用来搜集数据库的所有表
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/home.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/home.html
index 56b8fbd..1441148 100644
--- a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/home.html
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/home.html
@@ -256,8 +256,13 @@
 		</div>
 	</div>
 </div>
-<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=c59c0ec8058a8305009eb315584e07d1"></script>
-<script src="https://webapi.amap.com/maps?v=1.4.15&key=c59c0ec8058a8305009eb315584e07d1&plugin=AMap.MouseTool"></script>
+<script type="text/javascript">
+    window._AMapSecurityConfig = {
+        securityJsCode: "f4241876b072db561dc69b2857032738",
+    };
+</script>
+<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=fb70a54f977723c9cac44bc903936746"></script>
+<script src="https://webapi.amap.com/maps?v=1.4.15&key=fb70a54f977723c9cac44bc903936746&plugin=AMap.MouseTool"></script>
 <script type="text/javascript" src='https://a.amap.com/jsapi_demos/static/citys.js'></script>
 <script src="${ctxPath}/static/home.js"></script>
 <script src="${ctxPath}/static/js/jquery.sparkline 2.1.2.js"></script>
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount.html
new file mode 100644
index 0000000..37065c8
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount.html
@@ -0,0 +1,58 @@
+@layout("/common/_container.html"){
+<div class="row">
+    <div class="col-sm-12">
+        <div class="ibox float-e-margins">
+            <div class="ibox-title">
+                <h5>高德地图账号管理</h5>
+            </div>
+            <div class="ibox-content">
+                <div class="row row-lg">
+                    <div class="col-sm-12">
+                        <div class="row">
+                            <div class="col-sm-3">
+                                <#NameCon id="gdKey" name="高德key" />
+                            </div>
+                            <div class="col-sm-3">
+                                <#SelectCon id="useStatus" name="使用状态" >
+                                    <option value="">全部</option>
+                                    <option value="1">未使用</option>
+                                    <option value="2">使用中</option>
+                                    <option value="3">已用完</option>
+                                </#SelectCon>
+                            </div>
+                            <div class="col-sm-3">
+                                <#SelectCon id="status" name="状态" >
+                                    <option value="">全部</option>
+                                    <option value="1">启用</option>
+                                    <option value="2">禁用</option>
+                                </#SelectCon>
+                            </div>
+                            <div class="col-sm-3">
+                                <#button name="搜索" icon="fa-search" clickFun="TGaodeAccount.search()"/>
+                                <#button name="重置" icon="fa-trash" clickFun="TGaodeAccount.resetSearch()" space="true"/>
+                            </div>
+                        </div>
+                        <div class="hidden-xs" id="TGaodeAccountTableToolbar" role="group">
+                            @if(shiro.hasPermission("/tGaodeAccount/add")){
+                                <#button name="添加" icon="fa-plus" clickFun="TGaodeAccount.openAddTGaodeAccount()"/>
+                            @}
+                            @if(shiro.hasPermission("/tGaodeAccount/update")){
+                                <#button name="编辑" icon="fa-edit" clickFun="TGaodeAccount.openTGaodeAccountDetail()" space="true"/>
+                            @}
+                            @if(shiro.hasPermission("/tGaodeAccount/delete")){
+                                <#button name="删除" icon="fa-remove" clickFun="TGaodeAccount.delete()" space="true"/>
+                            @}
+                            @if(shiro.hasPermission("/tGaodeAccount/opt")){
+                                <#button name="启用" icon="fa-check-circle" clickFun="TGaodeAccount.enable()" space="true"/>
+                                <#button name="禁用" icon="fa-ban" clickFun="TGaodeAccount.disable()" space="true"/>
+                            @}
+                        </div>
+                        <#table id="TGaodeAccountTable"/>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</div>
+<script src="${ctxPath}/static/modular/system/tGaodeAccount/tGaodeAccount.js"></script>
+@}
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_add.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_add.html
new file mode 100644
index 0000000..02ec2a4
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_add.html
@@ -0,0 +1,32 @@
+@layout("/common/_container.html"){
+<div class="ibox float-e-margins">
+    <div class="ibox-content">
+        <div class="form-horizontal" id="gaodeAccountInfoForm">
+
+            <div class="row">
+                <div class="col-sm-10">
+                    <#input id="gdKey" name="高德key"/>
+                    <#select id="useStatus" name="使用状态:">
+                        <option value="1" selected="selected">未使用</option>
+                        <option value="2">使用中</option>
+                        <option value="3">已用完</option>
+                    </#select>
+                    <#select id="status" name="状态:">
+                        <option value="1" selected="selected">启用</option>
+                        <option value="2">禁用</option>
+                    </#select>
+                </div>
+            </div>
+
+            <div class="row btn-group-m-t">
+                <div class="col-sm-10 col-sm-offset-5">
+                    <#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="TGaodeAccountInfoDlg.addSubmit()"/>
+                    <#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="TGaodeAccountInfoDlg.close()"/>
+                </div>
+            </div>
+        </div>
+
+    </div>
+</div>
+<script src="${ctxPath}/static/modular/system/tGaodeAccount/tGaodeAccount_info.js"></script>
+@}
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_edit.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_edit.html
new file mode 100644
index 0000000..7af42a3
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tGaodeAccount/tGaodeAccount_edit.html
@@ -0,0 +1,32 @@
+@layout("/common/_container.html"){
+<div class="ibox float-e-margins">
+    <div class="ibox-content">
+        <div class="form-horizontal" id="gaodeAccountInfoForm">
+            <input type="hidden" id="id" name="id" value="${item.id}">
+            <div class="row">
+                <div class="col-sm-10">
+                    <#input id="gdKey" name="高德key" value="${item.gdKey}"/>
+                    <#select id="useStatus" name="使用状态:">
+                        <option value="1" ${1 == item.useStatus ? 'selected=selected' : ''}>未使用</option>
+                        <option value="2" ${2 == item.useStatus ? 'selected=selected' : ''}>使用中</option>
+                        <option value="3" ${3 == item.useStatus ? 'selected=selected' : ''}>已用完</option>
+                    </#select>
+                    <#select id="status" name="状态:">
+                        <option value="1" ${1 == item.status ? 'selected=selected' : ''}>启用</option>
+                        <option value="2" ${2 == item.status ? 'selected=selected' : ''}>禁用</option>
+                    </#select>
+                </div>
+            </div>
+
+            <div class="row btn-group-m-t">
+                <div class="col-sm-10 col-sm-offset-5">
+                    <#button btnCss="info" name="提交" id="ensure" icon="fa-check" clickFun="TGaodeAccountInfoDlg.editSubmit()"/>
+                    <#button btnCss="danger" name="取消" id="cancel" icon="fa-eraser" clickFun="TGaodeAccountInfoDlg.close()"/>
+                </div>
+            </div>
+        </div>
+
+    </div>
+</div>
+<script src="${ctxPath}/static/modular/system/tGaodeAccount/tGaodeAccount_info.js"></script>
+@}
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_add.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_add.html
index 284514e..447d2e8 100644
--- a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_add.html
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_add.html
@@ -164,7 +164,12 @@
 
     </div>
 </div>
-<script src="https://webapi.amap.com/maps?v=1.4.15&key=c59c0ec8058a8305009eb315584e07d1&plugin=AMap.MouseTool,AMap.DistrictSearch,AMap.PolyEditor,AMap.RectangleEditor,AMap.CircleEditor"></script>
+<script type="text/javascript">
+    window._AMapSecurityConfig = {
+        securityJsCode: "f4241876b072db561dc69b2857032738",
+    };
+</script>
+<script src="https://webapi.amap.com/maps?v=1.4.15&key=fb70a54f977723c9cac44bc903936746&plugin=AMap.MouseTool,AMap.DistrictSearch,AMap.PolyEditor,AMap.RectangleEditor,AMap.CircleEditor"></script>
 <script src="${ctxPath}/static/modular/system/tSite/electricFence.js"></script>
 <script src="${ctxPath}/static/modular/system/tSite/tSite_info.js"></script>
 @}
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_edit.html b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_edit.html
index 319a285..19a2b2f 100644
--- a/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_edit.html
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/WEB-INF/view/system/tSite/tSite_edit.html
@@ -187,7 +187,12 @@
 
     </div>
 </div>
-<script src="https://webapi.amap.com/maps?v=1.4.15&key=c59c0ec8058a8305009eb315584e07d1&plugin=AMap.MouseTool,AMap.DistrictSearch,AMap.PolyEditor,AMap.RectangleEditor,AMap.CircleEditor"></script>
+<script type="text/javascript">
+    window._AMapSecurityConfig = {
+        securityJsCode: "f4241876b072db561dc69b2857032738",
+    };
+</script>
+<script src="https://webapi.amap.com/maps?v=1.4.15&key=fb70a54f977723c9cac44bc903936746&plugin=AMap.MouseTool,AMap.DistrictSearch,AMap.PolyEditor,AMap.RectangleEditor,AMap.CircleEditor"></script>
 <script src="${ctxPath}/static/modular/system/tSite/electricFence.js"></script>
 <script src="${ctxPath}/static/modular/system/tSite/tSite_info.js"></script>
 @}
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount.js b/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount.js
new file mode 100644
index 0000000..3bdc6d2
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount.js
@@ -0,0 +1,257 @@
+/**
+ * 高德地图账号管理初始化
+ */
+var TGaodeAccount = {
+    id: "TGaodeAccountTable",	//表格id
+    seItem: null,		//选中的条目
+    table: null,
+    layerIndex: -1
+};
+
+/**
+ * 初始化表格的列
+ */
+TGaodeAccount.initColumn = function () {
+    return [
+        {field: 'selectItem', radio: true},
+        {title: '主键ID', field: 'id', visible: false, align: 'center', valign: 'middle'},
+        {title: '高德key', field: 'gdKey', visible: true, align: 'center', valign: 'middle',width:'20%',
+            formatter: function (value, row) {
+                var btn = "";
+                if(row.gdKey != '' && row.gdKey != null) {
+                    btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;" title="' + row.gdKey + '" onfocus="TUser.tooltip()">' + row.gdKey + '</p>']
+                }
+                return btn;
+            }
+        },
+        {title: '使用状态', field: 'useStatus', visible: true, align: 'center', valign: 'middle',
+            formatter: function (value, row) {
+                var btn = "";
+                if(row.useStatus != '' && row.useStatus != null) {
+                    if (row.useStatus == 1){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;" title="未使用" onfocus="TUser.tooltip()">未使用</p>']
+                    } else if (row.useStatus == 2){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color: #0d8ddb;" title="使用中" onfocus="TUser.tooltip()">使用中</p>']
+                    } else if (row.useStatus == 3){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color: red;" title="已用完" onfocus="TUser.tooltip()">已用完</p>']
+                    }
+                }
+                return btn;
+            }
+        },
+        {title: '状态', field: 'status', visible: true, align: 'center', valign: 'middle',
+            formatter: function (value, row) {
+                var btn = "";
+                if(row.status != '' && row.status != null) {
+                    if (row.status == 1){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color: #0d8ddb;" title="启用" onfocus="TUser.tooltip()">启用</p>']
+                    } else if (row.status == 2){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color: red;" title="禁用" onfocus="TUser.tooltip()">禁用</p>']
+                    }
+                }
+                return btn;
+            }
+        },
+        {title: '删除状态', field: 'delFlag', visible: true, align: 'center', valign: 'middle',
+            formatter: function (value, row) {
+                var btn = "";
+                if(row.delFlag != '' && row.delFlag != null) {
+                    if (row.delFlag == 0){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;" title="未删除" onfocus="TUser.tooltip()">未删除</p>']
+                    } else if (row.delFlag == 1){
+                        btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;color: red;" title="已删除" onfocus="TUser.tooltip()">已删除</p>']
+                    }
+                }
+                return btn;
+            }
+        },
+        {title: '添加时间', field: 'insertTime', visible: true, align: 'center', valign: 'middle',width:'12%',
+            formatter: function (value, row) {
+                var btn = "";
+                if(row.insertTime != '' && row.insertTime != null) {
+                    var time = row.insertTime.replace(" ",'<br>');
+                    btn = ['<p class="toolTip" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;" title="' + row.insertTime + '" onfocus="TUser.tooltip()">' + time + '</p>']
+                }
+                return btn;
+            }
+        }
+    ];
+};
+
+/**
+ * 检查是否选中
+ */
+TGaodeAccount.check = function () {
+    var selected = $('#' + this.id).bootstrapTable('getSelections');
+    if(selected.length == 0){
+        Feng.info("请先选中表格中的某一记录!");
+        return false;
+    }else{
+        TGaodeAccount.seItem = selected[0];
+        return true;
+    }
+};
+
+/**
+ * 点击添加高德地图账号
+ */
+TGaodeAccount.openAddTGaodeAccount = function () {
+    var index = layer.open({
+        type: 2,
+        title: '添加高德地图账号',
+        area: ['100%', '100%'], //宽高
+        fix: false, //不固定
+        maxmin: true,
+        content: Feng.ctxPath + '/tGaodeAccount/tGaodeAccount_add'
+    });
+    this.layerIndex = index;
+};
+
+/**
+ * 打开编辑高德地图账号
+ */
+TGaodeAccount.openTGaodeAccountDetail = function () {
+    if (this.check()) {
+        var index = layer.open({
+            type: 2,
+            title: '编辑高德地图账号',
+            area: ['100%', '100%'], //宽高
+            fix: false, //不固定
+            maxmin: true,
+            content: Feng.ctxPath + '/tGaodeAccount/tGaodeAccount_update/' + TGaodeAccount.seItem.id
+        });
+        this.layerIndex = index;
+    }
+};
+
+/**
+ * 删除高德地图账号
+ */
+TGaodeAccount.delete = function () {
+    if (this.check()) {
+        var gdKey = TGaodeAccount.seItem.gdKey;
+        if (gdKey == "" || gdKey == null || gdKey == undefined) {
+            gdKey = "该记录";
+        } else {
+            gdKey = "【" + gdKey + "】";
+        }
+        swal({
+            title: "您是否确认删除" + gdKey + "?",
+            text: "请谨慎操作,删除后不可恢复!",
+            type: "warning",
+            showCancelButton: true,
+            confirmButtonColor: "#DD6B55",
+            confirmButtonText: "删除",
+            closeOnConfirm: false
+        }, function () {
+            var ajax = new $ax(Feng.ctxPath + "/tGaodeAccount/delete", function (data) {
+                swal("删除成功", "您已经成功删除了" + gdKey + "。", "success");
+                TGaodeAccount.table.refresh();
+            }, function (data) {
+                swal("删除失败", data.responseJSON.message + "!", "warning");
+            });
+            ajax.set("tGaodeAccountId",TGaodeAccount.seItem.id);
+            ajax.start();
+        });
+    }
+};
+
+/**
+ * 启用
+ */
+TGaodeAccount.enable = function(){
+    if (this.check()) {
+        var gdKey = TGaodeAccount.seItem.gdKey;
+        if (gdKey == "" || gdKey == null || gdKey == undefined) {
+            gdKey = "该记录";
+        } else {
+            gdKey = "【" + gdKey + "】";
+        }
+        if (TGaodeAccount.seItem.status == 1) {
+            swal("启用失败", "【启用】状态下无需执行此操作", "warning");
+            return;
+        } else {
+            swal({
+                title: "您是否确认启用" + gdKey + "?",
+                text: "请谨慎操作!",
+                type: "warning",
+                showCancelButton: true,
+                confirmButtonColor: "#DD6B55",
+                confirmButtonText: "启用",
+                closeOnConfirm: false
+            }, function () {
+                var ajax = new $ax(Feng.ctxPath + "/tGaodeAccount/opt", function (data) {
+                    swal("启用成功", "您已经成功启用了" + gdKey + "。", "success");
+                    TGaodeAccount.table.refresh();
+                }, function (data) {
+                    swal("启用失败", data.responseJSON.message + "!", "warning");
+                });
+                ajax.set("tGaodeAccountId", TGaodeAccount.seItem.id);
+                ajax.set("optType", 1);
+                ajax.start();
+            });
+        }
+    }
+}
+
+/**
+ * 禁用
+ */
+TGaodeAccount.disable = function(){
+    if (this.check()) {
+        var gdKey = TGaodeAccount.seItem.gdKey;
+        if (gdKey == "" || gdKey == null || gdKey == undefined) {
+            gdKey = "该记录";
+        } else {
+            gdKey = "【" + gdKey + "】";
+        }
+        if (TGaodeAccount.seItem.status == 2) {
+            swal("禁用失败", "【禁用】状态下无需执行此操作", "warning");
+            return;
+        } else {
+            swal({
+                title: "您是否确认禁用" + gdKey + "?",
+                text: "请谨慎操作!",
+                type: "warning",
+                showCancelButton: true,
+                confirmButtonColor: "#DD6B55",
+                confirmButtonText: "禁用",
+                closeOnConfirm: false
+            }, function () {
+                var ajax = new $ax(Feng.ctxPath + "/tGaodeAccount/opt", function (data) {
+                    swal("禁用成功", "您已经成功禁用了" + gdKey + "。", "success");
+                    TGaodeAccount.table.refresh();
+                }, function (data) {
+                    swal("禁用失败", data.responseJSON.message + "!", "warning");
+                });
+                ajax.set("tGaodeAccountId", TGaodeAccount.seItem.id);
+                ajax.set("optType", 2);
+                ajax.start();
+            });
+        }
+    }
+}
+
+/**
+ * 查询高德地图账号列表
+ */
+TGaodeAccount.search = function () {
+    var queryData = {};
+    queryData['gdKey'] = $("#gdKey").val();
+    queryData['useStatus'] = $("#useStatus").val();
+    queryData['status'] = $("#status").val();
+    TGaodeAccount.table.refresh({query: queryData});
+};
+TGaodeAccount.resetSearch = function () {
+    $("#gdKey").val("");
+    $("#useStatus").val("");
+    $("#status").val("");
+    TGaodeAccount.search();
+};
+
+$(function () {
+    var defaultColunms = TGaodeAccount.initColumn();
+    var table = new BSTable(TGaodeAccount.id, "/tGaodeAccount/list", defaultColunms);
+    table.setPaginationType("server");
+    TGaodeAccount.table = table.init();
+});
diff --git a/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount_info.js b/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount_info.js
new file mode 100644
index 0000000..c69e5b4
--- /dev/null
+++ b/ManagementFBTravel/guns-admin/src/main/webapp/static/modular/system/tGaodeAccount/tGaodeAccount_info.js
@@ -0,0 +1,133 @@
+/**
+ * 初始化高德地图账号详情对话框
+ */
+var TGaodeAccountInfoDlg = {
+    gaodeAccountInfoData : {},
+    validateFields: {
+        gdKey: {
+            validators: {
+                notEmpty: {
+                    message: '高德key不能为空'
+                }
+            }
+        },
+        useStatus: {
+            validators: {
+                notEmpty: {
+                    message: '请先选择使用状态'
+                }
+            }
+        },
+        status: {
+            validators: {
+                notEmpty: {
+                    message: '请先选择状态'
+                }
+            }
+        },
+    }
+};
+
+/**
+ * 验证数据是否为空
+ */
+TGaodeAccountInfoDlg.validate = function () {
+    $('#gaodeAccountInfoForm').data("bootstrapValidator").resetForm();
+    $('#gaodeAccountInfoForm').bootstrapValidator('validate');
+    return $("#gaodeAccountInfoForm").data('bootstrapValidator').isValid();
+};
+
+
+/**
+ * 清除数据
+ */
+TGaodeAccountInfoDlg.clearData = function() {
+    this.gaodeAccountInfoData = {};
+}
+
+/**
+ * 设置对话框中的数据
+ *
+ * @param key 数据的名称
+ * @param val 数据的具体值
+ */
+TGaodeAccountInfoDlg.set = function(key, val) {
+    this.gaodeAccountInfoData[key] = (typeof val == "undefined") ? $("#" + key).val() : val;
+    return this;
+}
+
+/**
+ * 设置对话框中的数据
+ *
+ * @param key 数据的名称
+ * @param val 数据的具体值
+ */
+TGaodeAccountInfoDlg.get = function(key) {
+    return $("#" + key).val();
+}
+
+/**
+ * 关闭此对话框
+ */
+TGaodeAccountInfoDlg.close = function() {
+    parent.layer.close(window.parent.TGaodeAccount.layerIndex);
+}
+
+/**
+ * 收集数据
+ */
+TGaodeAccountInfoDlg.collectData = function() {
+    this
+    .set('id')
+    .set('gdKey')
+    .set('useStatus')
+    .set('status');
+}
+
+/**
+ * 提交添加
+ */
+TGaodeAccountInfoDlg.addSubmit = function() {
+
+    this.clearData();
+    this.collectData();
+    if(!this.validate()){
+        return ;
+    }
+    //提交信息
+    var ajax = new $ax(Feng.ctxPath + "/tGaodeAccount/add", function(data){
+        Feng.success("添加成功!");
+        window.parent.TGaodeAccount.table.refresh();
+        TGaodeAccountInfoDlg.close();
+    },function(data){
+        Feng.error("添加失败!" + data.responseJSON.message + "!");
+    });
+    ajax.set(this.gaodeAccountInfoData);
+    ajax.start();
+}
+
+/**
+ * 提交修改
+ */
+TGaodeAccountInfoDlg.editSubmit = function() {
+
+    this.clearData();
+    this.collectData();
+    if(!this.validate()){
+        return ;
+    }
+    //提交信息
+    var ajax = new $ax(Feng.ctxPath + "/tGaodeAccount/update", function(data){
+        Feng.success("修改成功!");
+        window.parent.TGaodeAccount.table.refresh();
+        TGaodeAccountInfoDlg.close();
+    },function(data){
+        Feng.error("修改失败!" + data.responseJSON.message + "!");
+    });
+    ajax.set(this.gaodeAccountInfoData);
+    ajax.start();
+}
+
+$(function() {
+    Feng.initValidator("gaodeAccountInfoForm", TGaodeAccountInfoDlg.validateFields);
+});

--
Gitblit v1.7.1