chore: 登录机制核实 + 样本离线渲染验证
- 登录: JSEncrypt RSA-2048, login2(/admin/tenant/auth), token=data.accessToken - tools/validate_samples.py: 复现 #17 散点/#18 网格等值面, 验证解析+色阶+异常逻辑 - 量化两剖面几何(夹角77.7度,十字支撑), 佐证可信体数据依赖(需>=3线/3D网格) - spec §8 更新登录细节; _validate 产物已忽略
This commit is contained in:
parent
667e97ed1b
commit
fe7737b175
|
|
@ -38,6 +38,7 @@ docs/proto*.jpeg
|
||||||
docs/tenant_login*.jpeg
|
docs/tenant_login*.jpeg
|
||||||
docs/docx_media/
|
docs/docx_media/
|
||||||
docs/_docx_media/
|
docs/_docx_media/
|
||||||
|
docs/_validate/
|
||||||
|
|
||||||
# ---- Large redundant archive (sample data kept unpacked in folder) ----
|
# ---- Large redundant archive (sample data kept unpacked in folder) ----
|
||||||
docs/剖面网格数据的色阶数据2等文件.tar
|
docs/剖面网格数据的色阶数据2等文件.tar
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,8 @@ IDatasetRepository {
|
||||||
- **API 基址** `http://tenant.geomative.cn/pop-api`(openresty 反代;OpenAPI 的 `/admin/*`、`/business/*` 加 `/pop-api` 前缀)。
|
- **API 基址** `http://tenant.geomative.cn/pop-api`(openresty 反代;OpenAPI 的 `/admin/*`、`/business/*` 加 `/pop-api` 前缀)。
|
||||||
- **认证头** `geomativeauthorization: Geomative <token>`(不透明会话令牌,非 JWT)。
|
- **认证头** `geomativeauthorization: Geomative <token>`(不透明会话令牌,非 JWT)。
|
||||||
- **登录三步**:① `GET /business/system/personalUser/getImageCode`→验证码图+`codeId` → ② `POST /business/system/personalUser/verifyCodeCheck {code,codeId}` → ③ `POST /admin/tenant/auth/login2 {username, password=RSA加密, checkCode}`→token。
|
- **登录三步**:① `GET /business/system/personalUser/getImageCode`→验证码图+`codeId` → ② `POST /business/system/personalUser/verifyCodeCheck {code,codeId}` → ③ `POST /admin/tenant/auth/login2 {username, password=RSA加密, checkCode}`→token。
|
||||||
|
- **密码加密 = JSEncrypt RSA-2048**(前端 vendor 用 JSEncrypt 库;密文 base64 ~344 字符 = 256 字节)。token 取响应 **`data.accessToken`**(值即 `"Geomative <hash>"`,存 web localStorage `token`)。
|
||||||
|
- 另有 `/email`、`/phone` 登录支线(非 M1)。
|
||||||
- 登录后:`getInfo` / `list-menus` / `enterprise/info` / `enterprise/joined/list`。
|
- 登录后:`getInfo` / `list-menus` / `enterprise/info` / `enterprise/joined/list`。
|
||||||
|
|
||||||
### 8.2 实现要点
|
### 8.2 实现要点
|
||||||
|
|
@ -234,7 +236,7 @@ IDatasetRepository {
|
||||||
|
|
||||||
抓取的真实流程里**未见 refresh-token 实际使用,login2 只返不透明会话 token**。因此:
|
抓取的真实流程里**未见 refresh-token 实际使用,login2 只返不透明会话 token**。因此:
|
||||||
|
|
||||||
- **RSA 公钥来源**待确认(内置 vs 接口取)。
|
- **RSA 公钥常量**待精确提取(机制已定:JSEncrypt RSA-2048;公钥在某懒加载 login 分包,实现登录时现场提取即可)。
|
||||||
- **token 生命周期 / 是否有 refresh 机制**待确认。据此二选一设计:
|
- **token 生命周期 / 是否有 refresh 机制**待确认。据此二选一设计:
|
||||||
- (a) 有 refresh token → 标准静默刷新、401 静默续期。
|
- (a) 有 refresh token → 标准静默刷新、401 静默续期。
|
||||||
- (b) 仅会话 token → 「免登录」= 持久化会话 token 至其有效期;**到期/401 引导用户重新登录(含验证码),不声称静默重登**。
|
- (b) 仅会话 token → 「免登录」= 持久化会话 token 至其有效期;**到期/401 引导用户重新登录(含验证码),不声称静默重登**。
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
样本数据离线验证 / 渲染基准生成器。
|
||||||
|
|
||||||
|
用途:在未搭好 Qt/VTK 环境前,用 Python(matplotlib) 复现剖面散点(#17)、网格等值面(#18)
|
||||||
|
渲染效果,验证「样本解析 + colorBar 色阶映射 + 异常叠加」逻辑正确;并量化两条剖面的几何
|
||||||
|
关系,为 dd_voxel 可信度(设计 §10/§14 K-10)提供依据。
|
||||||
|
|
||||||
|
产出的 PNG 作为后续 VTK 渲染的「地面真值」对照图。
|
||||||
|
|
||||||
|
运行:
|
||||||
|
python tools/validate_samples.py
|
||||||
|
输出:docs/_validate/ref_17_scatter.png, ref_18_grid.png(该目录已 .gitignore)
|
||||||
|
|
||||||
|
依赖:numpy, matplotlib
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import matplotlib
|
||||||
|
matplotlib.use("Agg")
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from matplotlib.colors import ListedColormap, BoundaryNorm
|
||||||
|
|
||||||
|
DATA = os.path.join(os.path.dirname(__file__), "..", "docs", "剖面网格数据的色阶数据2等文件")
|
||||||
|
OUT = os.path.join(os.path.dirname(__file__), "..", "docs", "_validate")
|
||||||
|
|
||||||
|
|
||||||
|
def load(name):
|
||||||
|
with open(os.path.join(DATA, name), encoding="utf-8") as f:
|
||||||
|
return json.load(f)["data"]
|
||||||
|
|
||||||
|
|
||||||
|
def parse_color(c):
|
||||||
|
"""支持 #RRGGBB 与 rgba(r,g,b,a);返回 0-1 RGB。"""
|
||||||
|
c = c.strip()
|
||||||
|
if c.startswith("#"):
|
||||||
|
return (int(c[1:3], 16) / 255, int(c[3:5], 16) / 255, int(c[5:7], 16) / 255)
|
||||||
|
nums = re.findall(r"[\d.]+", c)
|
||||||
|
return (float(nums[0]) / 255, float(nums[1]) / 255, float(nums[2]) / 255)
|
||||||
|
|
||||||
|
|
||||||
|
def colorbar(cb):
|
||||||
|
"""colorBar: [[value, color], ...] -> (sorted values, colors)。"""
|
||||||
|
pairs = sorted(((float(v), parse_color(c)) for v, c in cb), key=lambda p: p[0])
|
||||||
|
return np.array([p[0] for p in pairs]), [p[1] for p in pairs]
|
||||||
|
|
||||||
|
|
||||||
|
def render_scatter():
|
||||||
|
raw = load("剖面原数据1.txt")
|
||||||
|
vals, cols = colorbar(load("剖面原数据的色阶数据1.txt")["properties"]["colorBar"])
|
||||||
|
x, y, v = np.array(raw["xlist"]), np.array(raw["ylist"]), np.array(raw["vlist"])
|
||||||
|
cmap = ListedColormap(cols)
|
||||||
|
norm = BoundaryNorm(np.append(vals, vals[-1] * 1.2), cmap.N)
|
||||||
|
plt.figure(figsize=(11, 3.2))
|
||||||
|
plt.scatter(x, y, c=v, cmap=cmap, norm=norm, s=6, marker="s")
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.title("scatter (raw profile) ~#17")
|
||||||
|
plt.colorbar(shrink=0.7)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(os.path.join(OUT, "ref_17_scatter.png"), dpi=90)
|
||||||
|
plt.close()
|
||||||
|
print(f"[#17] pts={len(x)} x[{x.min():.1f},{x.max():.1f}] "
|
||||||
|
f"y[{y.min():.1f},{y.max():.1f}] v[{v.min():.1f},{v.max():.1f}]")
|
||||||
|
|
||||||
|
|
||||||
|
def render_grid():
|
||||||
|
g = load("剖面网格数据1.txt")
|
||||||
|
vals, cols = colorbar(load("剖面网格数据的色阶数据1.txt")["properties"]["colorBar"])
|
||||||
|
gx, gy, gv = np.array(g["x"]), np.array(g["y"]), np.array(g["v"]) # gv: [22][100]
|
||||||
|
X, Y = np.meshgrid(gx, gy)
|
||||||
|
plt.figure(figsize=(11, 3.0))
|
||||||
|
cf = plt.contourf(X, Y, gv, levels=vals, colors=cols[:len(vals) - 1])
|
||||||
|
plt.contour(X, Y, gv, levels=vals, colors="k", linewidths=0.4)
|
||||||
|
for a in load("剖面网格数据1——对应的异常圈定数据.txt"):
|
||||||
|
coord = a.get("location", {}).get("coordinate", [])
|
||||||
|
if coord and isinstance(coord[0], dict):
|
||||||
|
plt.plot([p["x"] for p in coord], [p["y"] for p in coord], "k--", lw=1.5)
|
||||||
|
plt.gca().invert_yaxis()
|
||||||
|
plt.title("grid bands + contour + anomaly ~#18")
|
||||||
|
plt.colorbar(cf, shrink=0.7)
|
||||||
|
plt.tight_layout()
|
||||||
|
plt.savefig(os.path.join(OUT, "ref_18_grid.png"), dpi=90)
|
||||||
|
plt.close()
|
||||||
|
print(f"[#18] grid V{gv.shape} vmin/max {g['vmin']:.1f}/{g['vmax']:.1f}")
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_voxel_geometry():
|
||||||
|
"""量化两条剖面几何关系:判断 dd_voxel 三维插值的数据支撑充分性。"""
|
||||||
|
def line(name):
|
||||||
|
r = load(name)
|
||||||
|
return np.column_stack([r["projectXList"], r["projectYList"]])
|
||||||
|
|
||||||
|
def principal_dir(p):
|
||||||
|
c = p - p.mean(0)
|
||||||
|
_, _, vt = np.linalg.svd(c, full_matrices=False)
|
||||||
|
return vt[0], p.mean(0)
|
||||||
|
|
||||||
|
p1, p2 = line("剖面原数据1.txt"), line("剖面原数据2.txt")
|
||||||
|
d1, c1 = principal_dir(p1)
|
||||||
|
d2, c2 = principal_dir(p2)
|
||||||
|
ang = np.degrees(np.arccos(abs(np.clip(d1 @ d2, -1, 1))))
|
||||||
|
n1 = np.array([-d1[1], d1[0]])
|
||||||
|
perp_gap = abs((c2 - c1) @ n1)
|
||||||
|
print(f"[voxel] line1 pts={len(p1)} line2 pts={len(p2)} | "
|
||||||
|
f"angle={ang:.1f}deg perp_gap={perp_gap:.1f}m "
|
||||||
|
f"=> {'crossing' if ang > 30 else 'sub-parallel'}; "
|
||||||
|
f"volume between lines is interpolated/extrapolated "
|
||||||
|
f"(credible voxel needs >=3 lines or a 3D grid)")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
os.makedirs(OUT, exist_ok=True)
|
||||||
|
render_scatter()
|
||||||
|
render_grid()
|
||||||
|
analyze_voxel_geometry()
|
||||||
|
print("written:", sorted(os.listdir(OUT)))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.stdout.reconfigure(encoding="utf-8")
|
||||||
|
main()
|
||||||
Loading…
Reference in New Issue