chore(repo): 导入 M-Z 业务底座 V1.9 基线并建立仓库规范
按周工交付的 SEC-Z-01 清理后源码建立 M-Z 主干,并按 Git 仓库惯例重排目录。 - aomin-gateway/ 后端工程 87 文件,原样保留,路径与构建命令未变 - demo/ 演示前端与设备模拟器 9 文件(原 02_前端与设备端),非正式三端 - docs/handover/ 交付与安全清理材料 6 份,内容未改 - docs/contract/ J-00 规格、OpenAPI、内部五接口、状态机、Mock 样例 - docs/reference/ 指纹与校验清单,含 84 个源码文件的 sha256 清单 目录重排只动位置不动内容:源码树 84 文件哈希与交付一致,逐文件自校验通过; 12 条 Flyway 迁移与交付包内镜像逐字节一致。 未纳入:迁移镜像目录(与工程内一套重复,改留指纹)、target/、证据 raw、 应急恢复脚本、评审用虚构台账数据。 安全:SEC-Z-01 15 处明文已清零,导入前重新扫描无新增命中,本仓库无历史污染。 行尾按交付字节原样保存(.gitattributes 设 * -text),不做归一化以免整树摘要失效。
This commit is contained in:
commit
a7605ef8b8
121 files changed
+23629
No files matched your search
@@ -0,0 +1,252 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>选择家的位置</title>
|
||||
<!--
|
||||
百度地图选点(在线底图 + 离线兜底)
|
||||
─────────────────────────────────────────────────────────
|
||||
· 底图用百度 JS API v2.0,ak 从下方 AK 常量读;
|
||||
· **坐标系必须转**:百度用 BD-09,我们库里存 GCJ-02,两者差 500~600 米。
|
||||
取点后 bd09ToGcj02() 转换再回传,否则存进去的家会落在隔壁街道;
|
||||
· ak 失效 / 没网 / 白名单没放行时,3 秒内自动跳 map-offline.html,不让用户看白屏。
|
||||
-->
|
||||
<style>
|
||||
:root{--brand:#146b7a;--ink:#1b2430;--sub:#6b7784;--line:#e4eaef}
|
||||
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
|
||||
html,body{margin:0;height:100%;overflow:hidden}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;
|
||||
background:#eef2f4;color:var(--ink);font-size:14px;display:flex;flex-direction:column}
|
||||
.top{flex:0 0 auto;background:var(--brand);color:#fff;padding:11px 12px;display:flex;align-items:center;gap:9px;z-index:10}
|
||||
.top button{background:rgba(255,255,255,.16);border:0;color:#fff;border-radius:9px;padding:7px 11px;font-size:13px;cursor:pointer}
|
||||
.top h1{font-size:15px;margin:0;flex:1;font-weight:600}
|
||||
.stage{flex:1;min-height:200px;position:relative}
|
||||
#map{width:100%;height:100%}
|
||||
/* 中心准星:拖地图选点,比"点哪儿算哪儿"在手机上准得多 */
|
||||
#pin{position:absolute;left:50%;top:50%;transform:translate(-50%,-100%);pointer-events:none;z-index:5}
|
||||
#pin svg{filter:drop-shadow(0 2px 4px rgba(0,0,0,.35))}
|
||||
#pinTip{position:absolute;left:50%;top:50%;transform:translate(-50%,6px);font-size:10.5px;
|
||||
color:#fff;background:rgba(20,40,55,.62);padding:2px 8px;border-radius:10px;pointer-events:none;z-index:5}
|
||||
#loading{position:absolute;inset:0;background:#f2f6f8;display:flex;align-items:center;justify-content:center;
|
||||
flex-direction:column;gap:10px;z-index:8;font-size:13px;color:var(--sub)}
|
||||
#loading .sp{width:26px;height:26px;border:3px solid #d6e2e6;border-top-color:var(--brand);border-radius:50%;
|
||||
animation:spin .9s linear infinite}
|
||||
@keyframes spin{to{transform:rotate(360deg)}}
|
||||
.bottom{flex:0 0 auto;background:#fff;border-top:1px solid var(--line);padding:10px 12px 12px;z-index:10}
|
||||
.addr{font-size:13px;color:var(--ink);margin-bottom:5px;min-height:18px;line-height:1.5;font-weight:600}
|
||||
.sub{font-size:11.5px;color:var(--sub);margin-bottom:9px;line-height:1.5}
|
||||
.coord{font-family:Consolas,Menlo,monospace;font-size:11.5px;color:var(--brand);margin-bottom:9px}
|
||||
.row{display:flex;gap:7px;align-items:center;margin-bottom:8px}
|
||||
.row input{flex:1;min-width:0;border:1px solid var(--line);border-radius:8px;padding:8px 9px;font-size:12.5px;outline:none}
|
||||
.btn{border:0;border-radius:9px;padding:11px 14px;font-size:14px;font-weight:600;cursor:pointer}
|
||||
.btn-main{background:var(--brand);color:#fff;width:100%}
|
||||
.btn-main:disabled{background:#c3d3d7}
|
||||
.btn-line{background:#fff;border:1px solid var(--line);color:var(--ink);white-space:nowrap}
|
||||
.BMap_cpyCtrl,.anchorBL{display:none!important}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="top">
|
||||
<button onclick="cancel()">← 返回</button>
|
||||
<h1>选择家的位置</h1>
|
||||
<button onclick="locate()">定位</button>
|
||||
</div>
|
||||
<div class="stage">
|
||||
<div id="map"></div>
|
||||
<div id="pin"><svg width="30" height="40" viewBox="0 0 30 40">
|
||||
<path d="M15 0C6.7 0 0 6.7 0 15c0 11 15 25 15 25s15-14 15-25C30 6.7 23.3 0 15 0z" fill="#146b7a"/>
|
||||
<circle cx="15" cy="15" r="5.5" fill="#fff"/></svg></div>
|
||||
<div id="pinTip">拖动地图,把准星对准你家</div>
|
||||
<div id="loading"><div class="sp"></div><span id="ldTxt">正在加载地图…</span></div>
|
||||
</div>
|
||||
<div class="bottom">
|
||||
<div class="addr" id="addr">拖动地图选择位置</div>
|
||||
<div class="sub" id="sub">地址会自动识别,选不准可以手动改</div>
|
||||
<div class="coord" id="coord">坐标:—(GCJ-02)</div>
|
||||
<div class="row">
|
||||
<input id="mlng" placeholder="经度 113.39" inputmode="decimal">
|
||||
<input id="mlat" placeholder="纬度 22.52" inputmode="decimal">
|
||||
<button class="btn btn-line" onclick="applyManual()">填入</button>
|
||||
</div>
|
||||
<button class="btn btn-main" id="ok" onclick="confirmPick()">确定这个位置</button>
|
||||
</div>
|
||||
<script>
|
||||
/* 百度 ak —— 不写死在源码里:部署时把 __BAIDU_AK__ 替换成自己的 AK,
|
||||
或用 window.BAIDU_AK 注入;没有 AK 时本页会自动降级到离线地图。 */
|
||||
var AK = window.BAIDU_AK || '__BAIDU_AK__';
|
||||
|
||||
/* ================= 坐标转换(必须) =================
|
||||
百度 BD-09 / 国测局 GCJ-02 相差 500~600 米。
|
||||
库里存 GCJ-02,所以「取点 → 转 GCJ」,「显示已知点 → 转 BD」。 */
|
||||
function bd09ToGcj02(bdLng, bdLat) {
|
||||
var x = bdLng - 0.0065, y = bdLat - 0.006;
|
||||
var z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * Math.PI * 3000 / 180);
|
||||
var t = Math.atan2(y, x) - 0.000003 * Math.cos(x * Math.PI * 3000 / 180);
|
||||
return { lng: z * Math.cos(t), lat: z * Math.sin(t) };
|
||||
}
|
||||
function gcj02ToBd09(lng, lat) {
|
||||
var z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * Math.PI * 3000 / 180);
|
||||
var t = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * Math.PI * 3000 / 180);
|
||||
return { lng: z * Math.cos(t) + 0.0065, lat: z * Math.sin(t) + 0.006 };
|
||||
}
|
||||
|
||||
var map = null, marker = null, geocoder = null;
|
||||
var cur = null; // 当前选的 GCJ-02 坐标
|
||||
var geoTimer = null;
|
||||
var HOME = { lng: 113.3926, lat: 22.5176 }; // 中山市政府(GCJ-02)
|
||||
|
||||
function fallback(reason) {
|
||||
var t = document.getElementById('ldTxt');
|
||||
if (t) t.textContent = reason + ',切换到离线地图…';
|
||||
setTimeout(function () { location.replace('map-offline.html'); }, 700);
|
||||
}
|
||||
|
||||
function initMap() {
|
||||
if (map) return; // callback 和轮询都可能触发,只认第一次
|
||||
try {
|
||||
map = new BMap.Map('map', { enableMapClick: false });
|
||||
var c = gcj02ToBd09(HOME.lng, HOME.lat);
|
||||
map.centerAndZoom(new BMap.Point(c.lng, c.lat), 16);
|
||||
map.enableScrollWheelZoom(true);
|
||||
map.enableDragging();
|
||||
geocoder = new BMap.Geocoder();
|
||||
document.getElementById('loading').style.display = 'none';
|
||||
map.addEventListener('moveend', onMoveEnd);
|
||||
onMoveEnd();
|
||||
} catch (e) {
|
||||
fallback('地图初始化失败');
|
||||
}
|
||||
}
|
||||
|
||||
/* 地图停稳后取中心点,转成 GCJ-02 并反查地址 */
|
||||
function onMoveEnd() {
|
||||
if (!map) return;
|
||||
var c = map.getCenter();
|
||||
var g = bd09ToGcj02(c.lng, c.lat);
|
||||
cur = { lng: +g.lng.toFixed(6), lat: +g.lat.toFixed(6) };
|
||||
document.getElementById('coord').textContent =
|
||||
'坐标:' + cur.lng + ', ' + cur.lat + '(GCJ-02)';
|
||||
document.getElementById('mlng').value = cur.lng;
|
||||
document.getElementById('mlat').value = cur.lat;
|
||||
|
||||
// 逆地理编码要联网,慢一点,节流 400ms,别拖一下发十个请求
|
||||
clearTimeout(geoTimer);
|
||||
geoTimer = setTimeout(function () {
|
||||
if (!geocoder) return;
|
||||
geocoder.getLocation(new BMap.Point(c.lng, c.lat), function (r) {
|
||||
if (!r) { return; }
|
||||
var a = r.address || {};
|
||||
var parts = [a.province, a.city, a.district, a.street, a.streetNumber].filter(Boolean);
|
||||
var poi = (r.surroundingPois && r.surroundingPois[0]) ? r.surroundingPois[0].title : '';
|
||||
// 街道名常常拼不出完整地址(百度在小区内部只回商圈),所以依次退:街道串 → 最近POI → 商圈
|
||||
var main = parts.join('') || poi || a.business || '已选位置';
|
||||
document.getElementById('addr').textContent = main;
|
||||
document.getElementById('sub').textContent = poi && main !== poi
|
||||
? '附近:' + poi
|
||||
: '地址已识别,可手动补充门牌';
|
||||
});
|
||||
}, 400);
|
||||
}
|
||||
|
||||
function applyManual() {
|
||||
var lng = parseFloat(document.getElementById('mlng').value);
|
||||
var lat = parseFloat(document.getElementById('mlat').value);
|
||||
if (!isFinite(lng) || !isFinite(lat)) { alert('请填入有效的经纬度数字'); return; }
|
||||
if (lng < 112.5 || lng > 114.5 || lat < 21.5 || lat > 23.5) {
|
||||
alert('这个坐标不在中山附近,请填 113.x / 22.x'); return;
|
||||
}
|
||||
cur = { lng: +lng.toFixed(6), lat: +lat.toFixed(6) };
|
||||
var b = gcj02ToBd09(lng, lat);
|
||||
if (map) { map.centerAndZoom(new BMap.Point(b.lng, b.lat), 17); }
|
||||
}
|
||||
|
||||
function locate() {
|
||||
if (!navigator.geolocation) { alert('这个浏览器不支持定位'); return; }
|
||||
navigator.geolocation.getCurrentPosition(function (p) {
|
||||
// 浏览器给的是 WGS-84,百度要 BD-09:先粗转 GCJ 再转 BD(市域内误差 <10m)
|
||||
var g = wgs84ToGcj02(p.coords.longitude, p.coords.latitude);
|
||||
var b = gcj02ToBd09(g.lng, g.lat);
|
||||
if (map) map.centerAndZoom(new BMap.Point(b.lng, b.lat), 17);
|
||||
}, function () {
|
||||
alert('定位失败(可能是没授权或信号不好),直接拖地图选吧');
|
||||
}, { timeout: 8000 });
|
||||
}
|
||||
|
||||
/* WGS-84 → GCJ-02(国内加密偏移的常用近似实现) */
|
||||
function wgs84ToGcj02(lng, lat) {
|
||||
var a = 6378245.0, ee = 0.00669342162296594323;
|
||||
var dLat = tfLat(lng - 105, lat - 35), dLng = tfLng(lng - 105, lat - 35);
|
||||
var radLat = lat / 180 * Math.PI, magic = Math.sin(radLat);
|
||||
magic = 1 - ee * magic * magic;
|
||||
var sqrtMagic = Math.sqrt(magic);
|
||||
dLat = (dLat * 180) / ((a * (1 - ee)) / (magic * sqrtMagic) * Math.PI);
|
||||
dLng = (dLng * 180) / (a / sqrtMagic * Math.cos(radLat) * Math.PI);
|
||||
return { lng: lng + dLng, lat: lat + dLat };
|
||||
}
|
||||
function tfLat(x, y) {
|
||||
var r = -100 + 2 * x + 3 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
|
||||
r += (20 * Math.sin(6 * x * Math.PI) + 20 * Math.sin(2 * x * Math.PI)) * 2 / 3;
|
||||
r += (20 * Math.sin(y * Math.PI) + 40 * Math.sin(y / 3 * Math.PI)) * 2 / 3;
|
||||
r += (160 * Math.sin(y / 12 * Math.PI) + 320 * Math.sin(y * Math.PI / 30)) * 2 / 3;
|
||||
return r;
|
||||
}
|
||||
function tfLng(x, y) {
|
||||
var r = 300 + x + 2 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
|
||||
r += (20 * Math.sin(6 * x * Math.PI) + 20 * Math.sin(2 * x * Math.PI)) * 2 / 3;
|
||||
r += (20 * Math.sin(x * Math.PI) + 40 * Math.sin(x / 3 * Math.PI)) * 2 / 3;
|
||||
r += (150 * Math.sin(x / 12 * Math.PI) + 300 * Math.sin(x / 30 * Math.PI)) * 2 / 3;
|
||||
return r;
|
||||
}
|
||||
|
||||
function confirmPick() {
|
||||
if (!cur) { alert('还没选位置'); return; }
|
||||
var addr = document.getElementById('addr').textContent || '';
|
||||
var d = {
|
||||
type: 'heserv:pick',
|
||||
lng: cur.lng, lat: cur.lat,
|
||||
name: addr.length > 24 ? addr.slice(0, 24) : addr,
|
||||
addr: addr,
|
||||
coordSys: 'GCJ-02',
|
||||
source: 'baidu'
|
||||
};
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage(d, '*');
|
||||
} else {
|
||||
alert('已选:' + d.lng + ', ' + d.lat);
|
||||
}
|
||||
}
|
||||
function cancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({ type: 'heserv:pick-cancel' }, '*');
|
||||
} else { history.back(); }
|
||||
}
|
||||
|
||||
/* ================= 加载百度脚本 =================
|
||||
注意:百度 v2.0 的 loader 内部用 document.write 注入主脚本。
|
||||
如果用 createElement 动态插入,write 在页面加载完后调用会被浏览器忽略,
|
||||
BMap 永远不出现 —— 表现就是"一直加载中,最后跳离线版"。
|
||||
所以这里必须用**静态 script 标签**,并靠 &callback= 拿加载完成的通知。 */
|
||||
function onBMapReady() {
|
||||
window.__bmapOk = true;
|
||||
setTimeout(initMap, 80);
|
||||
}
|
||||
|
||||
(function () {
|
||||
var timer = setInterval(function () {
|
||||
if (window.BMap && window.__bmapOk !== false) {
|
||||
clearInterval(timer);
|
||||
if (!map) initMap();
|
||||
return;
|
||||
}
|
||||
if (window.__bmapTries === undefined) window.__bmapTries = 0;
|
||||
if (++window.__bmapTries > 22) { // 约 4.4 秒还没起来
|
||||
clearInterval(timer);
|
||||
if (!map) fallback('地图加载超时');
|
||||
}
|
||||
}, 200);
|
||||
})();
|
||||
</script>
|
||||
<script src="https://api.map.baidu.com/api?v=2.0&ak=__BAIDU_AK__&callback=onBMapReady"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user